<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: M TOQEER ZIA</title>
    <description>The latest articles on DEV Community by M TOQEER ZIA (@m_toqeer).</description>
    <link>https://dev.to/m_toqeer</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3529850%2Fe40fd658-6577-41f6-b787-c57b8c4d9530.jpg</url>
      <title>DEV Community: M TOQEER ZIA</title>
      <link>https://dev.to/m_toqeer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/m_toqeer"/>
    <language>en</language>
    <item>
      <title>Horizontal vs. Vertical Scaling: Which One Should You Actually Use?</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Sat, 11 Jul 2026 11:32:21 +0000</pubDate>
      <link>https://dev.to/m_toqeer/horizontal-vs-vertical-scaling-which-one-should-you-actually-use-2913</link>
      <guid>https://dev.to/m_toqeer/horizontal-vs-vertical-scaling-which-one-should-you-actually-use-2913</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fygll42ayramg674ega56.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fygll42ayramg674ega56.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Every growing application eventually hits the same wall: the current infrastructure isn't enough. More users, more data, more requests per second — and suddenly "just add more resources" becomes a real engineering decision, not a throwaway line in a system design interview.&lt;/p&gt;

&lt;p&gt;That decision usually comes down to two paths: &lt;strong&gt;scale up&lt;/strong&gt; (vertical) or &lt;strong&gt;scale out&lt;/strong&gt; (horizontal). They sound like a matter of preference, but they come with very different tradeoffs in cost, complexity, and failure modes. Let's break both down.&lt;/p&gt;
&lt;h2&gt;
  
  
  Vertical Scaling: Make the Machine Bigger
&lt;/h2&gt;

&lt;p&gt;Vertical scaling (scaling up) means adding more power to a single machine — more CPU, more RAM, faster disks (e.g., moving from SSD to NVMe).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before: 4 vCPU, 16GB RAM
After:  16 vCPU, 64GB RAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On most cloud providers, this is often as simple as changing an instance type and restarting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example (AWS EC2):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stop the instance&lt;/span&gt;
aws ec2 stop-instances &lt;span class="nt"&gt;--instance-ids&lt;/span&gt; i-0123456789abcdef0

&lt;span class="c"&gt;# Resize&lt;/span&gt;
aws ec2 modify-instance-attribute &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--instance-id&lt;/span&gt; i-0123456789abcdef0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--instance-type&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Value&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;m5.2xlarge&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;

&lt;span class="c"&gt;# Start it back up&lt;/span&gt;
aws ec2 start-instances &lt;span class="nt"&gt;--instance-ids&lt;/span&gt; i-0123456789abcdef0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple.&lt;/strong&gt; No architecture changes, no distributed systems complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No data consistency issues.&lt;/strong&gt; One machine, one source of truth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Great for stateful workloads&lt;/strong&gt; like traditional relational databases that aren't built for sharding.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hard ceiling.&lt;/strong&gt; Eventually you hit the biggest instance type available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single point of failure.&lt;/strong&gt; If that one machine goes down, everything goes down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Downtime during resize&lt;/strong&gt;, in most setups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost grows non-linearly&lt;/strong&gt; — bigger machines get disproportionately more expensive.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Horizontal Scaling: Add More Machines
&lt;/h2&gt;

&lt;p&gt;Horizontal scaling (scaling out) means adding more instances of your application and distributing load across them, typically behind a load balancer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before: 1 server handling all traffic
After:  5 servers behind a load balancer, each handling ~20%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example (Docker Compose, scaling a service):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;--scale&lt;/span&gt; &lt;span class="nv"&gt;web&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example (Kubernetes, via Horizontal Pod Autoscaler):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling/v2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HorizontalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app-hpa&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Resource&lt;/span&gt;
      &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cpu&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Utilization&lt;/span&gt;
          &lt;span class="na"&gt;averageUtilization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;70&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No practical ceiling.&lt;/strong&gt; Add as many nodes as your budget and architecture allow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better fault tolerance.&lt;/strong&gt; One node dying doesn't take down the whole system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elastic cost.&lt;/strong&gt; Scale down during low traffic, scale up during peaks — pay for what you use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enables rolling deployments&lt;/strong&gt; with zero downtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Requires stateless design&lt;/strong&gt; (or careful state management via shared caches, sessions stores like Redis, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed systems problems appear&lt;/strong&gt;: data consistency, network latency, race conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More moving parts&lt;/strong&gt;: load balancers, service discovery, health checks, orchestration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging is harder&lt;/strong&gt; — logs and traces are spread across many nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Side-by-Side Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Vertical Scaling&lt;/th&gt;
&lt;th&gt;Horizontal Scaling&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Higher (distributed systems)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Upper limit&lt;/td&gt;
&lt;td&gt;Hardware ceiling&lt;/td&gt;
&lt;td&gt;Practically unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fault tolerance&lt;/td&gt;
&lt;td&gt;Single point of failure&lt;/td&gt;
&lt;td&gt;Resilient to node failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost curve&lt;/td&gt;
&lt;td&gt;Non-linear, gets expensive fast&lt;/td&gt;
&lt;td&gt;More linear, elastic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Downtime to scale&lt;/td&gt;
&lt;td&gt;Usually yes&lt;/td&gt;
&lt;td&gt;No (add/remove nodes live)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Traditional RDBMS, legacy monoliths&lt;/td&gt;
&lt;td&gt;Stateless services, microservices, web APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  So Which One Should You Pick?
&lt;/h2&gt;

&lt;p&gt;In practice, most real systems use &lt;strong&gt;both&lt;/strong&gt;, applied to different layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application/API layer&lt;/strong&gt; → horizontal scaling. Stateless services behind a load balancer scale out cleanly and give you fault tolerance for free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database layer&lt;/strong&gt; → often vertical scaling first (bigger instance, more RAM for caching, faster disks), because re-architecting for horizontal scaling (sharding, read replicas, distributed databases like CockroachDB or Cassandra) is a much bigger investment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache layer&lt;/strong&gt; (Redis, Memcached) → horizontal scaling via clustering once a single node's memory becomes the bottleneck.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common growth path looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start on a single small server (nothing to scale yet).&lt;/li&gt;
&lt;li&gt;Hit load limits → scale vertically (bigger box). Fastest fix, buys time.&lt;/li&gt;
&lt;li&gt;Vertical scaling gets expensive or hits a ceiling → move to horizontal scaling for the application tier.&lt;/li&gt;
&lt;li&gt;Database becomes the bottleneck → introduce read replicas, then sharding or a distributed database if needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Real Takeaway
&lt;/h2&gt;

&lt;p&gt;Vertical scaling buys you time with minimal complexity. Horizontal scaling buys you resilience and (near) unlimited growth at the cost of architectural complexity. Neither is "better" — the right call depends on where your current bottleneck actually is, how stateful your system is, and how much complexity your team can realistically operate.&lt;/p&gt;

&lt;p&gt;If you're not sure which one you need right now: profile first. Find out whether you're CPU-bound, memory-bound, I/O-bound, or connection-bound before reaching for either solution. Scaling the wrong dimension just gets you the same problem with a bigger bill.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have you had to make this call in production? What tipped the decision one way or the other for you — cost, team size, or the nature of the workload? Drop it in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Load Balancing Explained: The Complete Guide to Types and Algorithms</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Sat, 11 Jul 2026 11:27:34 +0000</pubDate>
      <link>https://dev.to/m_toqeer/load-balancing-explained-the-complete-guide-to-types-and-algorithms-4a61</link>
      <guid>https://dev.to/m_toqeer/load-balancing-explained-the-complete-guide-to-types-and-algorithms-4a61</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftfuj6r270edd9081n19p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftfuj6r270edd9081n19p.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;If you've ever wondered how sites like Amazon or Netflix handle millions of simultaneous users without crashing, the answer usually starts with one unsung hero of system design: &lt;strong&gt;the load balancer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we'll break down what load balancing is, why it matters, and the different types and algorithms you'll encounter in real-world architectures.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Load Balancing?
&lt;/h2&gt;

&lt;p&gt;Load balancing is the process of distributing incoming network traffic across multiple servers so that no single server becomes overwhelmed. Instead of one server handling every request, a load balancer sits in front of a group of servers (often called a &lt;strong&gt;server pool&lt;/strong&gt; or &lt;strong&gt;server farm&lt;/strong&gt;) and routes each incoming request to the server best equipped to handle it.&lt;/p&gt;

&lt;p&gt;Think of it like a checkout line at a grocery store. If everyone lines up at one register, that cashier gets overwhelmed while others sit idle. A good store manager (the load balancer) directs customers to open registers, keeping the whole line moving smoothly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Load Balancing Matters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High availability&lt;/strong&gt; – if one server fails, traffic is automatically rerouted to healthy servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; – you can add or remove servers based on demand without downtime&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; – requests are distributed efficiently, reducing latency&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redundancy&lt;/strong&gt; – protects against a single point of failure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt; – enables maintenance and deployments without taking the whole system offline&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How a Load Balancer Works
&lt;/h2&gt;

&lt;p&gt;At a high level, a load balancer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receives an incoming client request&lt;/li&gt;
&lt;li&gt;Checks the health/status of servers in the pool&lt;/li&gt;
&lt;li&gt;Applies a routing algorithm to pick a server&lt;/li&gt;
&lt;li&gt;Forwards the request to that server&lt;/li&gt;
&lt;li&gt;Returns the response back to the client&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most load balancers also perform continuous &lt;strong&gt;health checks&lt;/strong&gt;, pinging servers periodically to make sure they're still responsive before sending traffic their way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Types of Load Balancers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Hardware Load Balancers
&lt;/h3&gt;

&lt;p&gt;These are dedicated physical devices designed specifically to distribute traffic. They offer strong performance and reliability but come with a high upfront cost and limited flexibility. Common in large enterprises with strict compliance or performance requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; High throughput, dedicated resources, vendor support&lt;br&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; Expensive, less flexible, harder to scale dynamically&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Software Load Balancers
&lt;/h3&gt;

&lt;p&gt;These run as applications on standard servers or virtual machines (e.g., NGINX, HAProxy, Traefik). They're cheaper, easier to configure, and integrate well with cloud-native and containerized environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; Cost-effective, flexible, easy to automate&lt;br&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; Shares resources with the host machine, may need tuning for extreme scale&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Cloud-Based / Managed Load Balancers
&lt;/h3&gt;

&lt;p&gt;Services like AWS Elastic Load Balancer (ELB), Google Cloud Load Balancing, and Azure Load Balancer are fully managed offerings. They scale automatically and integrate tightly with other cloud services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; Auto-scaling, minimal maintenance, pay-as-you-go&lt;br&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; Vendor lock-in, less low-level control&lt;/p&gt;




&lt;h2&gt;
  
  
  Load Balancing by OSI Layer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Layer 4 (Transport Layer) Load Balancing
&lt;/h3&gt;

&lt;p&gt;Operates at the transport layer, making routing decisions based on IP address and TCP/UDP port information — without inspecting the actual content of the packet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faster&lt;/strong&gt; since it doesn't need to parse application data&lt;/li&gt;
&lt;li&gt;Doesn't understand HTTP headers, cookies, or URLs&lt;/li&gt;
&lt;li&gt;Good for simple, high-throughput scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Layer 7 (Application Layer) Load Balancing
&lt;/h3&gt;

&lt;p&gt;Operates at the application layer, meaning it can inspect the actual content of requests — HTTP headers, URLs, cookies, and even request bodies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enables &lt;strong&gt;smart routing&lt;/strong&gt;, like sending &lt;code&gt;/api/*&lt;/code&gt; requests to one set of servers and &lt;code&gt;/images/*&lt;/code&gt; to another&lt;/li&gt;
&lt;li&gt;Supports SSL termination, content-based routing, and session persistence&lt;/li&gt;
&lt;li&gt;Slightly slower than Layer 4 due to deeper packet inspection&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Load Balancing Algorithms
&lt;/h2&gt;

&lt;p&gt;The algorithm determines &lt;em&gt;how&lt;/em&gt; the load balancer chooses which server gets the next request.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Round Robin
&lt;/h3&gt;

&lt;p&gt;Requests are distributed sequentially across the server pool, one after another. Simple and effective when all servers have similar capacity.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Weighted Round Robin
&lt;/h3&gt;

&lt;p&gt;Similar to round robin, but servers are assigned weights based on their capacity. More powerful servers receive a proportionally larger share of traffic.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Least Connections
&lt;/h3&gt;

&lt;p&gt;Routes traffic to the server with the fewest active connections. Ideal when requests vary significantly in processing time.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Weighted Least Connections
&lt;/h3&gt;

&lt;p&gt;Combines the "least connections" logic with server capacity weighting — factoring in both current load and server power.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. IP Hash
&lt;/h3&gt;

&lt;p&gt;Uses the client's IP address to consistently route them to the same server, useful for maintaining session persistence without needing a shared session store.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Least Response Time
&lt;/h3&gt;

&lt;p&gt;Sends traffic to the server with the fastest response time and fewest active connections, optimizing for speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Random / Random with Two Choices
&lt;/h3&gt;

&lt;p&gt;Requests are distributed randomly, sometimes with a "power of two choices" optimization where the balancer picks the less-loaded of two randomly selected servers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Global Server Load Balancing (GSLB)
&lt;/h2&gt;

&lt;p&gt;Beyond distributing traffic across servers in one data center, &lt;strong&gt;GSLB&lt;/strong&gt; distributes traffic across multiple data centers or geographic regions. This is essential for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reducing latency by routing users to the nearest region&lt;/li&gt;
&lt;li&gt;Disaster recovery if an entire region goes down&lt;/li&gt;
&lt;li&gt;Compliance with data residency requirements&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Load Balancing vs. Reverse Proxy
&lt;/h2&gt;

&lt;p&gt;These terms are often confused. A &lt;strong&gt;reverse proxy&lt;/strong&gt; sits in front of servers and forwards client requests, but its primary job may be caching, SSL termination, or security — not necessarily distributing traffic across multiple backend servers. A &lt;strong&gt;load balancer&lt;/strong&gt; is specifically focused on distributing traffic to prevent overload. In practice, many tools (like NGINX and HAProxy) can act as both.&lt;/p&gt;




&lt;h2&gt;
  
  
  Choosing the Right Load Balancer
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Consideration&lt;/th&gt;
&lt;th&gt;Recommendation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Simple traffic distribution&lt;/td&gt;
&lt;td&gt;Round Robin or Least Connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session persistence needed&lt;/td&gt;
&lt;td&gt;IP Hash or Layer 7 with sticky sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mixed server capacities&lt;/td&gt;
&lt;td&gt;Weighted Round Robin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-based routing&lt;/td&gt;
&lt;td&gt;Layer 7 load balancer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Global user base&lt;/td&gt;
&lt;td&gt;GSLB with regional data centers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud-native infrastructure&lt;/td&gt;
&lt;td&gt;Managed cloud load balancer (ELB, GCP LB, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Load balancing is a foundational concept in building scalable, resilient systems. Whether you're running a small side project or architecting infrastructure for millions of users, understanding these types and algorithms helps you make informed decisions about reliability and performance.&lt;/p&gt;

&lt;p&gt;The right choice ultimately depends on your traffic patterns, infrastructure, and business requirements — there's no one-size-fits-all solution, but now you have the vocabulary and mental model to reason through it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Found this useful? Feel free to share your own load balancing setups or war stories in the comments!&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The New HTTP QUERY Method: Why It Exists and What Problem It Actually Solves</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Fri, 10 Jul 2026 19:36:50 +0000</pubDate>
      <link>https://dev.to/m_toqeer/the-new-http-query-method-why-it-exists-and-what-problem-it-actually-solves-1fkp</link>
      <guid>https://dev.to/m_toqeer/the-new-http-query-method-why-it-exists-and-what-problem-it-actually-solves-1fkp</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ferbnpuk5uf1qhr2n8m47.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ferbnpuk5uf1qhr2n8m47.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've spent any time building backend systems, you know the HTTP verbs by heart: GET, POST, PUT, PATCH, DELETE. For decades, that list felt complete. Recently, though, a new method has entered the conversation — &lt;strong&gt;QUERY&lt;/strong&gt;. Before diving into what it does, it's worth understanding &lt;em&gt;why&lt;/em&gt; it was needed in the first place, because the reasoning tells you a lot about how the web actually works under the hood.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP Isn't a Network Protocol — It's an Agreement
&lt;/h2&gt;

&lt;p&gt;A common misconception is that HTTP is a network-level protocol like TCP or UDP. It isn't. HTTP sits at the application layer, built on top of TCP, which handles the actual transport of data between machines.&lt;/p&gt;

&lt;p&gt;Here's the thing about TCP: it doesn't care what you send. You could open a TCP connection between two machines and transmit the string "hello," and it would arrive just fine. But that string carries no meaning. Is it a greeting? A command? Data to be saved? TCP has no concept of intent — it just moves bytes from one point to another.&lt;/p&gt;

&lt;p&gt;This is the exact problem HTTP was designed to solve. Instead of every developer sending arbitrary, unstructured strings across the wire, HTTP introduced a standardized way to express &lt;em&gt;intent&lt;/em&gt;. That's really what an HTTP method is: a declaration of what you're trying to do.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GET&lt;/strong&gt; → I intend to retrieve something&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;POST&lt;/strong&gt; → I intend to create something&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PUT&lt;/strong&gt; → I intend to replace something&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PATCH&lt;/strong&gt; → I intend to partially update something&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DELETE&lt;/strong&gt; → I intend to remove something&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the method comes the resource name (like &lt;code&gt;/users&lt;/code&gt;), and after that, optional extras — headers (key-value metadata) and a body (the actual payload). This simple structure is what allows every server and client in the world, regardless of who built them, to understand each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where GET Requests Start to Break Down
&lt;/h2&gt;

&lt;p&gt;GET requests carry their parameters in the URL itself, using query strings — anything after the &lt;code&gt;?&lt;/code&gt;. This works beautifully for simple filtering: &lt;code&gt;/users?name=piyush&lt;/code&gt; is clean, readable, and easy to reason about.&lt;/p&gt;

&lt;p&gt;The trouble starts when your filtering needs grow. Real-world applications often need to combine multiple conditions — filter by name, restrict by age, match an email domain, sort, paginate, and more, all in a single request. Try to cram that into a query string and you run into real constraints:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;URL length limits.&lt;/strong&gt; Most browsers and servers cap URLs around 8,000 characters. Complex filters can blow past that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encoding overhead.&lt;/strong&gt; Spaces and special characters aren't allowed raw in URLs — everything needs to go through &lt;code&gt;encodeURIComponent&lt;/code&gt; or similar, making complex queries messy and error-prone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exposure in logs.&lt;/strong&gt; Since query parameters live in the URL, they show up in server logs, browser history, and proxy logs — not ideal if any of that data is sensitive.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Workaround Everyone Used (and Why It Was Broken)
&lt;/h2&gt;

&lt;p&gt;Faced with these limits, developers found a workaround: if GET can't hold a complex query, just use POST instead. A POST request has a body, and a body can hold arbitrarily complex, structured JSON — filters, search terms, nested conditions, whatever you need, with no length restrictions and no awkward encoding.&lt;/p&gt;

&lt;p&gt;So teams started building endpoints like &lt;code&gt;POST /getUsers&lt;/code&gt;, reading the filter criteria from &lt;code&gt;request.body&lt;/code&gt;, and running the query on the backend. Functionally, it worked. But it broke the semantic contract of REST.&lt;/p&gt;

&lt;p&gt;The resource name says "get users." The method says "I intend to create something." That mismatch isn't just a style nitpick — it has real technical consequences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;POST requests are never cacheable.&lt;/strong&gt; Caching systems (whether at the CDN layer or elsewhere) assume that identical POST requests might produce different side effects each time, so they're excluded from caching by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;POST requests are not idempotent.&lt;/strong&gt; Idempotency means that calling an operation repeatedly with the same input produces the same result every time. GET is naturally idempotent — calling &lt;code&gt;GET /users/1&lt;/code&gt; a thousand times returns the same user a thousand times, with no side effects. POST is the opposite: call &lt;code&gt;POST /users&lt;/code&gt; five times with the same payload, and you'll likely end up with five different records, because POST's entire purpose is to create something new each time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the "use POST for complex reads" trick solved the encoding problem but created a caching and correctness problem. You couldn't cache these disguised read operations at all, even though they were, semantically, just reads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter the QUERY Method
&lt;/h2&gt;

&lt;p&gt;This is precisely the gap the new HTTP QUERY method fills. Conceptually, it's simple: QUERY behaves like GET — safe, cacheable, and idempotent — but it allows a request body, just like POST.&lt;/p&gt;

&lt;p&gt;That combination is exactly what was missing. With QUERY:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your intent is unambiguous: you're reading data, not creating or mutating it.&lt;/li&gt;
&lt;li&gt;You can send arbitrarily complex filter logic in the request body — no URL length limits, no manual encoding gymnastics.&lt;/li&gt;
&lt;li&gt;Because the method itself signals "this is a safe, repeatable read," CDNs and caching layers can treat QUERY requests as cacheable, the same way they treat GET.&lt;/li&gt;
&lt;li&gt;Because it's idempotent, retry logic, deduplication, and other reliability patterns that depend on idempotency all work correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, QUERY resolves a long-standing architectural tension between GET and POST — the need for expressive, complex read requests without sacrificing cacheability or correctness.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Should You Actually Use It?
&lt;/h2&gt;

&lt;p&gt;This doesn't mean GET is obsolete. For simple lookups and filters — a handful of query parameters — GET with query strings remains perfectly fine and arguably more transparent, since the full request is visible in the URL itself.&lt;/p&gt;

&lt;p&gt;QUERY becomes the better choice when your read operations get complex enough that expressing them in a URL is impractical: multi-field search, nested filters, large parameter sets, or anything that previously would have forced you into the POST workaround.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bigger Lesson
&lt;/h2&gt;

&lt;p&gt;It's worth remembering that REST conventions — GET fetches, POST creates, PUT updates — aren't laws of physics. They're self-imposed rules the developer community agreed on to keep systems interoperable. Nothing stops your server from working if you send data with a method named "hello" instead of GET. The value of these conventions is entirely in the shared understanding they create between client, server, and every piece of infrastructure (caches, proxies, logging tools) sitting in between.&lt;/p&gt;

&lt;p&gt;The QUERY method is a good example of how these conventions evolve: not by breaking the system, but by formalizing a pattern developers were already reaching for through workarounds, and giving it the semantics it always should have had.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building a Microservices App with Kubernetes: What I Learned the Hard Way</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Tue, 07 Jul 2026 12:52:32 +0000</pubDate>
      <link>https://dev.to/m_toqeer/building-a-microservices-app-with-kubernetes-what-i-learned-the-hard-way-5h95</link>
      <guid>https://dev.to/m_toqeer/building-a-microservices-app-with-kubernetes-what-i-learned-the-hard-way-5h95</guid>
      <description>&lt;p&gt;From Docker to Minikube, Ingress, Services, and Skaffold in one real project&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I did not learn Kubernetes by reading theory alone. I learned it by building a real microservices app, breaking things, fixing them, and slowly seeing how all the parts fit together.&lt;/p&gt;

&lt;p&gt;The project was a simple blogging app with posts and comments, but the architecture behind it was the real lesson. Instead of putting everything into one big backend, I split the app into small services: Posts, Comments, Moderation, Query, and an Event Bus. The frontend was a React client. Each service had one clear job. That choice forced me to understand containers, service discovery, deployments, networking, ingress, and local Kubernetes with Minikube.&lt;/p&gt;

&lt;p&gt;This is my learning journey written in simple English. I am sharing what I built, why I built it this way, what confused me, and what finally made the whole picture click.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction to the Project&lt;/li&gt;
&lt;li&gt;Understanding Containers&lt;/li&gt;
&lt;li&gt;Kubernetes Basics&lt;/li&gt;
&lt;li&gt;Kubernetes Architecture&lt;/li&gt;
&lt;li&gt;Deployments&lt;/li&gt;
&lt;li&gt;Services&lt;/li&gt;
&lt;li&gt;Load Balancing&lt;/li&gt;
&lt;li&gt;Communication Between Microservices&lt;/li&gt;
&lt;li&gt;Ingress Controller&lt;/li&gt;
&lt;li&gt;Host File Configuration&lt;/li&gt;
&lt;li&gt;Minikube&lt;/li&gt;
&lt;li&gt;Minikube IP&lt;/li&gt;
&lt;li&gt;Docker Inside Minikube&lt;/li&gt;
&lt;li&gt;Skaffold&lt;/li&gt;
&lt;li&gt;Important Commands Explained&lt;/li&gt;
&lt;li&gt;Common Problems I Faced&lt;/li&gt;
&lt;li&gt;Pros and Cons&lt;/li&gt;
&lt;li&gt;Lessons I Learned&lt;/li&gt;
&lt;li&gt;Best Practices&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;What’s Next?&lt;/li&gt;
&lt;li&gt;SEO Details&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Introduction to the Project
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is this project?
&lt;/h3&gt;

&lt;p&gt;I built a small blogging app where users can create posts and add comments. The interesting part is not the app idea itself. The interesting part is how the app behaves behind the scenes.&lt;/p&gt;

&lt;p&gt;The system is split into multiple services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Posts Service creates posts&lt;/li&gt;
&lt;li&gt;Comments Service creates comments&lt;/li&gt;
&lt;li&gt;Moderation Service checks comments and approves or rejects them&lt;/li&gt;
&lt;li&gt;Query Service keeps a read-optimized view for the UI&lt;/li&gt;
&lt;li&gt;Event Bus forwards events between services&lt;/li&gt;
&lt;li&gt;React Client shows the user interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This project helped me understand event-driven microservices, CQRS, and eventual consistency. In simple words, one service does not try to do everything. Instead, each service does one thing well and talks to others through events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why microservices?
&lt;/h3&gt;

&lt;p&gt;I asked myself a very practical question: why not just build one backend?&lt;/p&gt;

&lt;p&gt;The answer became clearer as the project grew. A monolithic app is easier at the beginning, but it can become heavy later. Every change affects the same codebase and one bug can slow down the whole system.&lt;/p&gt;

&lt;p&gt;Microservices solved a few real problems for me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each service could be built and understood separately&lt;/li&gt;
&lt;li&gt;Each service could be deployed separately&lt;/li&gt;
&lt;li&gt;One slow service did not need to block the others&lt;/li&gt;
&lt;li&gt;It was easier to model real business flow as events&lt;/li&gt;
&lt;li&gt;I could practice service-to-service communication the way larger systems do it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why not a monolithic application?
&lt;/h3&gt;

&lt;p&gt;I did think about a monolith first. For a small demo, that would have been simpler. But my goal was learning, not just shipping the shortest possible code.&lt;/p&gt;

&lt;p&gt;If I had used one monolith, I would have missed the hard but useful parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How services discover each other&lt;/li&gt;
&lt;li&gt;How Kubernetes manages containers&lt;/li&gt;
&lt;li&gt;Why ingress matters&lt;/li&gt;
&lt;li&gt;Why internal services use ClusterIP&lt;/li&gt;
&lt;li&gt;How async events keep the system flexible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I chose the harder path because it taught me more.&lt;/p&gt;

&lt;h3&gt;
  
  
  What problems microservices solve
&lt;/h3&gt;

&lt;p&gt;Microservices help when different parts of an application need to move at different speeds.&lt;/p&gt;

&lt;p&gt;For example, in my project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Posts are created quickly&lt;/li&gt;
&lt;li&gt;Comments may need moderation&lt;/li&gt;
&lt;li&gt;The UI reads from a separate query model&lt;/li&gt;
&lt;li&gt;The system should not freeze just because one service is busy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the kind of problem microservices handle well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture overview
&lt;/h3&gt;

&lt;p&gt;Here is the high-level picture I worked with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React Client
    |
    v
Ingress
    |
    +------------------------+
    |                        |
    v                        v
Posts Service           Query Service
    |                        ^
    v                        |
Event Bus --------------&amp;gt; Moderation Service
    |
    v
Comments Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flow is event-based. A request starts in the client, goes to a service, and then that service emits an event to the event bus. The event bus shares that event with the other services that care about it.&lt;/p&gt;

&lt;p&gt;That separation was one of the most useful lessons in the whole journey.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Understanding Containers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Docker?
&lt;/h3&gt;

&lt;p&gt;Docker was my entry point into this whole path. Before Docker, I used to think, “Why does an app work on my machine but fail somewhere else?” Docker made that question smaller.&lt;/p&gt;

&lt;p&gt;Docker lets me package an application with everything it needs to run: code, runtime, dependencies, and configuration. That package is called an image. When the image runs, it becomes a container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why containers exist
&lt;/h3&gt;

&lt;p&gt;Containers exist because software environments are messy.&lt;/p&gt;

&lt;p&gt;One machine may have Node.js 16. Another may have Node.js 20. One machine may have missing packages. Another may have a different operating system. Containers reduce that problem by giving the app a predictable environment.&lt;/p&gt;

&lt;p&gt;The easiest way I understood it was this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An image is the blueprint&lt;/li&gt;
&lt;li&gt;A container is the running house built from that blueprint&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Images vs containers
&lt;/h3&gt;

&lt;p&gt;This confused me at first, so I kept it simple.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image: the saved template&lt;/li&gt;
&lt;li&gt;Container: the live running instance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I build the same image ten times, I get ten containers. They all come from the same starting point, but each container runs separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Kubernetes needs Docker
&lt;/h3&gt;

&lt;p&gt;Strictly speaking, Kubernetes does not require Docker specifically anymore, but in my learning path Docker was the tool that built the container images Kubernetes used.&lt;/p&gt;

&lt;p&gt;Kubernetes does not care how the image was built. It cares that the image exists and can be pulled by a node. Docker helped me create those images in a familiar way.&lt;/p&gt;

&lt;h3&gt;
  
  
  How containers communicate
&lt;/h3&gt;

&lt;p&gt;In the project, containers communicate over the network. Each service listens on a port, and other services call that port using HTTP.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Posts Service listens on port 8000&lt;/li&gt;
&lt;li&gt;Comments Service listens on port 8001&lt;/li&gt;
&lt;li&gt;Query Service listens on port 8002&lt;/li&gt;
&lt;li&gt;Moderation Service listens on port 8003&lt;/li&gt;
&lt;li&gt;Event Bus listens on port 5000&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One service sends a request to another service using its network address and port. That is simple in theory, but in Kubernetes it becomes easier when we use Services and DNS names instead of raw IP addresses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple example
&lt;/h3&gt;

&lt;p&gt;If I want the Posts Service to send an event, it posts to the Event Bus endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Posts Service -&amp;gt; http://event-bus-srv:5000/events
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That internal address is much better than hardcoding a Pod IP, because Pods can change.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Kubernetes Basics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Kubernetes?
&lt;/h3&gt;

&lt;p&gt;Kubernetes is a system that helps me run containers across one or more machines. It handles placement, restarts, scaling, and networking.&lt;/p&gt;

&lt;p&gt;The easiest way I can describe it is this: Docker runs containers, but Kubernetes organizes them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Kubernetes exists
&lt;/h3&gt;

&lt;p&gt;I used to think Kubernetes was just a fancy way to run Docker. It is not.&lt;/p&gt;

&lt;p&gt;It exists because running one container is easy, but running many containers reliably is hard. Once I had more than one service, I started asking real orchestration questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What if a container dies?&lt;/li&gt;
&lt;li&gt;What if traffic increases?&lt;/li&gt;
&lt;li&gt;Which machine should run which container?&lt;/li&gt;
&lt;li&gt;How do services find each other?&lt;/li&gt;
&lt;li&gt;How do I update a service without breaking everything?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kubernetes helps answer those questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  What problems Kubernetes solves
&lt;/h3&gt;

&lt;p&gt;Kubernetes solves a few practical problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It restarts failed containers&lt;/li&gt;
&lt;li&gt;It spreads containers across nodes&lt;/li&gt;
&lt;li&gt;It scales applications up and down&lt;/li&gt;
&lt;li&gt;It gives containers stable network identities through Services&lt;/li&gt;
&lt;li&gt;It supports rolling updates&lt;/li&gt;
&lt;li&gt;It makes local and production setups more similar&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cluster
&lt;/h3&gt;

&lt;p&gt;A cluster is the whole Kubernetes environment. It is the group of machines that work together.&lt;/p&gt;

&lt;p&gt;I like to think of it like a small company. The company is the cluster. Inside it, there are different employees doing different jobs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node
&lt;/h3&gt;

&lt;p&gt;A node is one machine inside the cluster. It is where Pods run.&lt;/p&gt;

&lt;p&gt;If the cluster is the company, the node is one office building.&lt;/p&gt;

&lt;h3&gt;
  
  
  Master Node or Control Plane
&lt;/h3&gt;

&lt;p&gt;The master node, also called the control plane, is the brain of Kubernetes.&lt;/p&gt;

&lt;p&gt;It decides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which node gets a Pod&lt;/li&gt;
&lt;li&gt;What happens when a Pod dies&lt;/li&gt;
&lt;li&gt;When replicas should be created or removed&lt;/li&gt;
&lt;li&gt;How the cluster stays in the desired state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I do not normally run my app there. I let it manage the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worker Node
&lt;/h3&gt;

&lt;p&gt;Worker nodes are the machines that actually run my Pods and containers.&lt;/p&gt;

&lt;p&gt;If the control plane is the manager, worker nodes are the people doing the actual work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pod
&lt;/h3&gt;

&lt;p&gt;A Pod is the smallest deployable unit in Kubernetes.&lt;/p&gt;

&lt;p&gt;This was one of my biggest mental shifts. Kubernetes does not usually run a raw container directly. It runs a Pod, and the Pod contains one or more containers.&lt;/p&gt;

&lt;p&gt;I usually used one container per Pod in this project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Container inside a Pod
&lt;/h3&gt;

&lt;p&gt;A container inside a Pod is the actual process running my app.&lt;/p&gt;

&lt;p&gt;The Pod gives it networking and shared storage if needed. The container is still the thing running Node.js or React.&lt;/p&gt;

&lt;h3&gt;
  
  
  Replica
&lt;/h3&gt;

&lt;p&gt;A replica is another copy of the same Pod.&lt;/p&gt;

&lt;p&gt;If one Pod is not enough to handle traffic, Kubernetes can run two, three, or more copies. That helped me understand scaling in a very simple way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Namespace
&lt;/h3&gt;

&lt;p&gt;A namespace is a way to separate resources inside the same cluster.&lt;/p&gt;

&lt;p&gt;I think of it like separate rooms inside the same building. Everything is still inside the cluster, but the rooms help keep things organized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service
&lt;/h3&gt;

&lt;p&gt;A Service gives Pods a stable network identity.&lt;/p&gt;

&lt;p&gt;This matters because Pods can come and go. If I try to talk to a Pod directly, the address may change. A Service gives me one stable name and forwards traffic to the matching Pods.&lt;/p&gt;

&lt;p&gt;That idea became very important later when I explained ClusterIP and internal service communication.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Kubernetes Architecture
&lt;/h2&gt;

&lt;p&gt;Once I understood the pieces, I needed to understand how they connect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
   |
   v
Ingress Controller
   |
   v
Service
   |
   v
Pod
   |
   v
Container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How the connection works
&lt;/h3&gt;

&lt;p&gt;The request usually starts from the browser.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The browser sends traffic to a host name such as posts.com&lt;/li&gt;
&lt;li&gt;The Ingress Controller receives the request&lt;/li&gt;
&lt;li&gt;Ingress routes the request to the correct Service&lt;/li&gt;
&lt;li&gt;The Service finds a matching Pod&lt;/li&gt;
&lt;li&gt;The Pod forwards the traffic to the container running the app&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That chain is what made Kubernetes feel real to me. It is not random. It is a path.&lt;/p&gt;

&lt;h3&gt;
  
  
  A larger picture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  +----------------------+
                  |   Kubernetes Cluster |
                  +----------+-----------+
                             |
           +-----------------+-----------------+
           |                                   |
           v                                   v
     Worker Node 1                        Worker Node 2
           |                                   |
        Pod(s)                              Pod(s)
           |                                   |
      Container(s)                       Container(s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cluster decides where the Pods go. The nodes run them. Services give access to them. Ingress gives the outside world one entry point.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Deployments
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Deployments exist
&lt;/h3&gt;

&lt;p&gt;When I first saw a Deployment YAML, I wondered why I could not just create a Pod directly and stop there.&lt;/p&gt;

&lt;p&gt;The answer is that Pods are temporary, but Deployments manage Pods for me.&lt;/p&gt;

&lt;p&gt;A Deployment makes sure the desired number of Pod replicas exists. If a Pod dies, the Deployment creates a new one. If I want to update the app, it helps perform a rolling update.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Pods the right way
&lt;/h3&gt;

&lt;p&gt;I used Deployments instead of manually creating Pods because I wanted Kubernetes to manage the lifecycle.&lt;/p&gt;

&lt;p&gt;For example, the Posts service deployment looks like this in spirit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;posts-depl&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;posts&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;posts&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;posts&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;toqeer43553/posts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What each part means
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;apiVersion: apps/v1&lt;/code&gt; means I am using the apps API group&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kind: Deployment&lt;/code&gt; means this object manages Pods&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;metadata.name&lt;/code&gt; gives the Deployment a name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spec.replicas: 1&lt;/code&gt; asks Kubernetes to keep one Pod running&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spec.selector.matchLabels&lt;/code&gt; tells the Deployment which Pods belong to it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spec.template&lt;/code&gt; is the Pod template&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spec.template.metadata.labels&lt;/code&gt; must match the selector&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spec.template.spec.containers&lt;/code&gt; defines the container inside the Pod&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;image&lt;/code&gt; tells Kubernetes which image to run&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Replica management
&lt;/h3&gt;

&lt;p&gt;If I change &lt;code&gt;replicas&lt;/code&gt; from 1 to 3, Kubernetes should keep three Pods alive.&lt;/p&gt;

&lt;p&gt;That is useful when traffic grows. It is also useful when I want redundancy. If one Pod crashes, the others can still serve traffic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rolling updates
&lt;/h3&gt;

&lt;p&gt;Rolling updates mean I can replace old Pods with new ones gradually.&lt;/p&gt;

&lt;p&gt;That is safer than shutting down everything at once.&lt;/p&gt;

&lt;p&gt;The benefit is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fewer outages&lt;/li&gt;
&lt;li&gt;less risk&lt;/li&gt;
&lt;li&gt;easier rollback if something breaks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Self healing
&lt;/h3&gt;

&lt;p&gt;Self healing was one of the most satisfying things to watch.&lt;/p&gt;

&lt;p&gt;If I deleted a Pod manually, the Deployment created a replacement. That taught me the meaning of “desired state.” I say what I want. Kubernetes tries to keep it true.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling
&lt;/h3&gt;

&lt;p&gt;Scaling becomes easy once a Deployment owns the Pods.&lt;/p&gt;

&lt;p&gt;Instead of managing each container by hand, I can ask for more replicas and let Kubernetes handle the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I needed Deployments in this project
&lt;/h3&gt;

&lt;p&gt;I had six app components. I did not want to manually babysit each one. Deployments gave me a controlled way to run them all and recover from failures.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Services
&lt;/h2&gt;

&lt;p&gt;Services were one of the most important concepts I learned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Services exist
&lt;/h3&gt;

&lt;p&gt;Pods are temporary. Their IP addresses can change. That means one service cannot safely call another by Pod IP.&lt;/p&gt;

&lt;p&gt;A Service gives me a stable name and a stable way to reach matching Pods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service types
&lt;/h3&gt;

&lt;p&gt;I learned four common Service types.&lt;/p&gt;

&lt;h4&gt;
  
  
  ClusterIP
&lt;/h4&gt;

&lt;p&gt;ClusterIP is the default service type. It exposes the service only inside the cluster.&lt;/p&gt;

&lt;p&gt;I used ClusterIP for almost all internal services in this project.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;only other services inside Kubernetes need access&lt;/li&gt;
&lt;li&gt;you want internal service discovery&lt;/li&gt;
&lt;li&gt;you do not want public access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;secure by default&lt;/li&gt;
&lt;li&gt;stable internal address&lt;/li&gt;
&lt;li&gt;great for microservice-to-microservice communication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;not reachable directly from outside the cluster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;posts-clusterip-srv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;comments-srv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;query-srv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;event-bus-srv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;moderation-srv&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  NodePort
&lt;/h4&gt;

&lt;p&gt;NodePort exposes a service on a port on every node.&lt;/p&gt;

&lt;p&gt;I used it for the Posts service in the project to help with external access in some learning setups.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;you want a simple way to access a service from outside&lt;/li&gt;
&lt;li&gt;you are learning or prototyping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simple to understand&lt;/li&gt;
&lt;li&gt;easy to test locally&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;less flexible than Ingress&lt;/li&gt;
&lt;li&gt;awkward for many services&lt;/li&gt;
&lt;li&gt;not ideal for production&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  LoadBalancer
&lt;/h4&gt;

&lt;p&gt;LoadBalancer asks a cloud provider to create an external load balancer.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;you are in a cloud environment&lt;/li&gt;
&lt;li&gt;you want a public entry point with managed infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simple cloud integration&lt;/li&gt;
&lt;li&gt;external traffic routing is handled for you&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;depends on cloud support&lt;/li&gt;
&lt;li&gt;not very useful in a pure local Minikube setup&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ExternalName
&lt;/h4&gt;

&lt;p&gt;ExternalName maps a service name to an external DNS name.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Kubernetes needs to refer to something outside the cluster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simple DNS aliasing&lt;/li&gt;
&lt;li&gt;useful for external dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;does not act like normal proxy routing&lt;/li&gt;
&lt;li&gt;not good for every use case&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real examples from my project
&lt;/h3&gt;

&lt;p&gt;The internal services all use ClusterIP so that one service can talk to another by name.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://event-bus-srv:5000/events
http://comments-srv:8001/events
http://query-srv:8002/events
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was much cleaner than hardcoding IPs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I chose ClusterIP for internal communication
&lt;/h3&gt;

&lt;p&gt;Because the services talk to each other inside the cluster.&lt;/p&gt;

&lt;p&gt;I did not want the browser or the public internet calling my internal moderation service directly. ClusterIP kept those services private while still making them reachable from inside the cluster.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Load Balancing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why load balancing is important
&lt;/h3&gt;

&lt;p&gt;If one service gets a lot of traffic, one Pod may not be enough. Load balancing spreads requests across available Pods.&lt;/p&gt;

&lt;p&gt;That matters because it improves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;performance&lt;/li&gt;
&lt;li&gt;reliability&lt;/li&gt;
&lt;li&gt;availability&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Kubernetes balances traffic
&lt;/h3&gt;

&lt;p&gt;When I send traffic to a Service, Kubernetes forwards it to one of the matching Pods.&lt;/p&gt;

&lt;p&gt;If there are multiple replicas, the Service acts like a traffic distributor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
  |
  v
Service
  |
  +-------&amp;gt; Pod 1
  +-------&amp;gt; Pod 2
  +-------&amp;gt; Pod 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What happens if one Pod crashes
&lt;/h3&gt;

&lt;p&gt;If a Pod crashes, the Deployment replaces it.&lt;/p&gt;

&lt;p&gt;If traffic is still flowing, the Service stops sending requests to the dead Pod and keeps using the healthy ones.&lt;/p&gt;

&lt;p&gt;That gave me a lot more confidence in Kubernetes. It was not just running containers. It was actively keeping the system alive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple example
&lt;/h3&gt;

&lt;p&gt;If I had three replicas of the Query service, the Service could send requests to any healthy replica.&lt;/p&gt;

&lt;p&gt;That means users would not care which exact Pod answered. They only care that the app works.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Communication Between Microservices
&lt;/h2&gt;

&lt;p&gt;This is where the project became interesting.&lt;/p&gt;

&lt;h3&gt;
  
  
  The event flow I built
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Posts Service
    |
    v
Event Bus
    |
    v
Query Service

Comments Service
    |
    v
Event Bus
    |
    +-------------------+
    |                   |
    v                   v
Moderation Service   Query Service
    |
    v
Event Bus
    |
    v
Comments Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data does not move in a straight line like a normal form submit. It moves as events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why ClusterIP is used here
&lt;/h3&gt;

&lt;p&gt;Because these services should talk privately inside the cluster.&lt;/p&gt;

&lt;p&gt;The browser does not need to know where Moderation lives. The browser only talks to the public entry point. The internal services talk to each other through internal DNS names such as &lt;code&gt;query-srv&lt;/code&gt; or &lt;code&gt;event-bus-srv&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not use Pod IPs
&lt;/h3&gt;

&lt;p&gt;Because Pod IPs are temporary.&lt;/p&gt;

&lt;p&gt;If a Pod restarts, Kubernetes may assign a new IP. That would break hardcoded service addresses.&lt;/p&gt;

&lt;p&gt;Using service names solves that problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service discovery
&lt;/h3&gt;

&lt;p&gt;Service discovery means services can find each other by name.&lt;/p&gt;

&lt;p&gt;I did not need to ask, “What is the IP address of the Event Bus today?” I could just use the service DNS name.&lt;/p&gt;

&lt;p&gt;That is a huge reason Kubernetes feels manageable once the basics click.&lt;/p&gt;

&lt;h3&gt;
  
  
  Internal DNS
&lt;/h3&gt;

&lt;p&gt;Inside the cluster, a service name becomes a DNS entry.&lt;/p&gt;

&lt;p&gt;That is why code like this works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://event-bus-srv:5000/events
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service name is resolved inside Kubernetes, not by my laptop’s normal DNS setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example from the project
&lt;/h3&gt;

&lt;p&gt;When the Posts service creates a post, it stores it locally and then sends a &lt;code&gt;PostCreated&lt;/code&gt; event to the Event Bus.&lt;/p&gt;

&lt;p&gt;The Event Bus forwards that event to the Query service, which updates the read model.&lt;/p&gt;

&lt;p&gt;That is the central idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;write side changes data&lt;/li&gt;
&lt;li&gt;event bus shares the change&lt;/li&gt;
&lt;li&gt;read side updates asynchronously&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is event-driven microservices in plain language.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Ingress Controller
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Ingress exists
&lt;/h3&gt;

&lt;p&gt;Before Ingress, each service needed its own exposure strategy.&lt;/p&gt;

&lt;p&gt;That becomes messy fast.&lt;/p&gt;

&lt;p&gt;Ingress gives me one external entry point and lets me route requests based on host or path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problems before Ingress
&lt;/h3&gt;

&lt;p&gt;Without Ingress, I would have needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple NodePorts&lt;/li&gt;
&lt;li&gt;manual routing logic outside the cluster&lt;/li&gt;
&lt;li&gt;more open ports&lt;/li&gt;
&lt;li&gt;a harder mental model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not fun once a project grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  One entry point
&lt;/h3&gt;

&lt;p&gt;Ingress lets me say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;requests to &lt;code&gt;/create-post&lt;/code&gt; go to the Posts service&lt;/li&gt;
&lt;li&gt;requests to &lt;code&gt;/get-posts&lt;/code&gt; go to the Query service&lt;/li&gt;
&lt;li&gt;requests to &lt;code&gt;/post/.../comments&lt;/code&gt; go to the Comments service&lt;/li&gt;
&lt;li&gt;everything else goes to the React client&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Host-based routing
&lt;/h3&gt;

&lt;p&gt;The host in my setup is &lt;code&gt;posts.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That means the app can be reached by a friendly domain instead of by a raw IP and port.&lt;/p&gt;

&lt;h3&gt;
  
  
  Path-based routing
&lt;/h3&gt;

&lt;p&gt;Path-based routing means different URL paths go to different backend services.&lt;/p&gt;

&lt;p&gt;Here is the idea in my project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;posts.com/create-post  -&amp;gt; Posts Service
posts.com/get-posts    -&amp;gt; Query Service
posts.com/post/...     -&amp;gt; Comments Service
posts.com/             -&amp;gt; Client Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  My ingress configuration
&lt;/h3&gt;

&lt;p&gt;The real Ingress manifest uses the nginx ingress class and a regex path for the comments route.&lt;/p&gt;

&lt;p&gt;That setup lets Kubernetes route requests to the correct service without the browser needing to know internal service names.&lt;/p&gt;

&lt;h3&gt;
  
  
  How a request travels
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser
  |
  v
posts.com/get-posts
  |
  v
Ingress Controller
  |
  v
query-srv
  |
  v
Query Pod
  |
  v
Response to browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That path was one of the clearest signs that I was learning real Kubernetes networking, not just memorizing YAML.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Host File Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why I edited the hosts file
&lt;/h3&gt;

&lt;p&gt;My browser needs to know what &lt;code&gt;posts.com&lt;/code&gt; means.&lt;/p&gt;

&lt;p&gt;In local development, that name does not exist on the public internet. So I had to teach my laptop to map &lt;code&gt;posts.com&lt;/code&gt; to the Minikube IP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;127.0.0.1 posts.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, more commonly in Minikube setups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Minikube IP&amp;gt; posts.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why browsers need this
&lt;/h3&gt;

&lt;p&gt;When I type a domain into the browser, the browser asks DNS where to send the request.&lt;/p&gt;

&lt;p&gt;If the domain is only for local development, I need a manual mapping. The hosts file gives me that mapping.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I learned
&lt;/h3&gt;

&lt;p&gt;This part felt small at first, but it was very important.&lt;/p&gt;

&lt;p&gt;If the host file is wrong, Ingress may be working perfectly and the browser will still fail. That made me realize how many layers exist between “type URL” and “see page.”&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Minikube
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Minikube?
&lt;/h3&gt;

&lt;p&gt;Minikube is a local Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;It lets me practice Kubernetes on my own machine without needing a cloud account or a production cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why use Minikube
&lt;/h3&gt;

&lt;p&gt;I used Minikube because it made learning possible.&lt;/p&gt;

&lt;p&gt;It gave me a safe place to test things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployments&lt;/li&gt;
&lt;li&gt;Services&lt;/li&gt;
&lt;li&gt;Ingress&lt;/li&gt;
&lt;li&gt;Pods&lt;/li&gt;
&lt;li&gt;DNS&lt;/li&gt;
&lt;li&gt;local image handling&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Local Kubernetes
&lt;/h3&gt;

&lt;p&gt;Minikube is Kubernetes, but small and local.&lt;/p&gt;

&lt;p&gt;That was perfect for me because I could test, break, and retry quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cluster creation
&lt;/h3&gt;

&lt;p&gt;I learned that starting a cluster is the first step before applying manifests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That command gives me a local cluster to work with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cluster deletion
&lt;/h3&gt;

&lt;p&gt;When I wanted a clean restart, I could delete the cluster and create it again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube delete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That saved me many times when I had a messy local state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Status
&lt;/h3&gt;

&lt;p&gt;I used status checks to make sure the cluster was healthy before blaming my YAML.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dashboard
&lt;/h3&gt;

&lt;p&gt;The Minikube dashboard helped me see what was running.&lt;/p&gt;

&lt;p&gt;Seeing Pods, Services, and Deployments in a UI made the system much less abstract.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing services
&lt;/h3&gt;

&lt;p&gt;Minikube also helped me access Services through IPs and tunnel-like behavior depending on the setup.&lt;/p&gt;

&lt;p&gt;That became especially important when I started learning NodePort, Ingress, and the hosts file.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Minikube IP
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Minikube has its own IP
&lt;/h3&gt;

&lt;p&gt;Minikube runs as its own local Kubernetes environment. It is not the same thing as my laptop’s &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That means the cluster may have a separate IP address.&lt;/p&gt;

&lt;h3&gt;
  
  
  localhost vs Minikube IP
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;localhost&lt;/code&gt; means my own machine.&lt;/p&gt;

&lt;p&gt;Minikube IP means the address where the Minikube cluster can be reached.&lt;/p&gt;

&lt;p&gt;These are sometimes related, but they are not the same thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why NodePort works
&lt;/h3&gt;

&lt;p&gt;NodePort exposes a port on the node.&lt;/p&gt;

&lt;p&gt;If I know the Minikube IP and the NodePort, I can reach the service from outside the cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why localhost sometimes works
&lt;/h3&gt;

&lt;p&gt;In some setups, Minikube is close enough to my local environment that &lt;code&gt;localhost&lt;/code&gt; can work through port forwarding or driver-specific behavior.&lt;/p&gt;

&lt;p&gt;That made me realize there is no single universal local Kubernetes setup. The exact access path depends on the driver and cluster configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Internal networking
&lt;/h3&gt;

&lt;p&gt;Inside the cluster, Services and Pods talk on the internal Kubernetes network.&lt;/p&gt;

&lt;p&gt;Outside the cluster, I need Ingress, NodePort, port forwarding, or another access method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple diagram
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Laptop browser
    |
    v
localhost or Minikube IP
    |
    v
NodePort / Ingress
    |
    v
Service
    |
    v
Pod
    |
    v
Container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That separation helped me understand why some URLs worked and some did not.&lt;/p&gt;




&lt;h2&gt;
  
  
  13. Docker Inside Minikube
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How Docker works inside Minikube
&lt;/h3&gt;

&lt;p&gt;This was a painful but useful lesson.&lt;/p&gt;

&lt;p&gt;I first built images on my laptop and expected Minikube to see them automatically.&lt;/p&gt;

&lt;p&gt;That is because Minikube often uses its own image environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why images are built inside Minikube
&lt;/h3&gt;

&lt;p&gt;If Kubernetes inside Minikube tries to pull an image, it needs that image to exist in a place it can access.&lt;/p&gt;

&lt;p&gt;When I build locally, my host Docker may have the image. But Minikube’s cluster may not see it unless I either push it to a registry or build it in Minikube’s Docker environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Kubernetes cannot see local Docker images
&lt;/h3&gt;

&lt;p&gt;This was one of my most confusing early mistakes.&lt;/p&gt;

&lt;p&gt;I had the image on my machine, so I assumed Kubernetes would just use it. But the cluster is not my laptop shell. The cluster is its own environment.&lt;/p&gt;

&lt;p&gt;That is why image visibility matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  docker-env
&lt;/h3&gt;

&lt;p&gt;The Minikube Docker environment helps me build images directly into Minikube’s image store.&lt;/p&gt;

&lt;p&gt;The command looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eval $(minikube docker-env)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this helps
&lt;/h3&gt;

&lt;p&gt;After running that command, my Docker CLI talks to Minikube’s Docker daemon instead of my local one.&lt;/p&gt;

&lt;p&gt;That means when I run &lt;code&gt;docker build&lt;/code&gt;, the image is built where Kubernetes can see it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple explanation
&lt;/h3&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My laptop Docker -&amp;gt; local image only
Minikube -&amp;gt; cannot see it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My laptop Docker CLI -&amp;gt; Minikube Docker daemon -&amp;gt; image available to Kubernetes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What I learned
&lt;/h3&gt;

&lt;p&gt;I stopped thinking of Docker as one global thing. It is really a client talking to a Docker environment.&lt;/p&gt;

&lt;p&gt;That small realization made Minikube much easier to work with.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Skaffold
&lt;/h2&gt;

&lt;p&gt;Skaffold was the tool that made the whole workflow feel smoother.&lt;/p&gt;

&lt;h3&gt;
  
  
  What problem Skaffold solves
&lt;/h3&gt;

&lt;p&gt;Without Skaffold, my workflow looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;edit code
 -&amp;gt; docker build
 -&amp;gt; docker push
 -&amp;gt; kubectl apply
 -&amp;gt; check rollout
 -&amp;gt; repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is slow and annoying during development.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Skaffold automates everything
&lt;/h3&gt;

&lt;p&gt;Skaffold watches files, rebuilds images, and redeploys Kubernetes resources for me.&lt;/p&gt;

&lt;p&gt;That means I can focus on changing code instead of repeating the same commands all day.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;skaffold dev&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This command starts a development loop.&lt;/p&gt;

&lt;p&gt;It watches for file changes and updates the cluster.&lt;/p&gt;

&lt;p&gt;That was huge for productivity because I could edit, save, and see changes with much less manual work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Image rebuild
&lt;/h3&gt;

&lt;p&gt;When source files change, Skaffold can rebuild the matching image.&lt;/p&gt;

&lt;h3&gt;
  
  
  File watching
&lt;/h3&gt;

&lt;p&gt;It watches my app files so I do not have to trigger everything manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sync
&lt;/h3&gt;

&lt;p&gt;For some files, Skaffold can sync changes directly into a running container instead of rebuilding every time.&lt;/p&gt;

&lt;p&gt;That makes the feedback loop faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto deployment
&lt;/h3&gt;

&lt;p&gt;When images change, Skaffold applies the Kubernetes manifests again.&lt;/p&gt;

&lt;p&gt;That closes the loop between code and cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hot reload
&lt;/h3&gt;

&lt;p&gt;In practice, it feels close to hot reload for the whole stack, even though the exact behavior depends on the app and file syncing setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  My Skaffold YAML
&lt;/h3&gt;

&lt;p&gt;The config in this project defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Kubernetes manifests to deploy&lt;/li&gt;
&lt;li&gt;the local build settings&lt;/li&gt;
&lt;li&gt;the images for client and each service&lt;/li&gt;
&lt;li&gt;the sync rules for JavaScript files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was a clean way to keep development repeatable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Skaffold mattered so much
&lt;/h3&gt;

&lt;p&gt;It reduced friction.&lt;/p&gt;

&lt;p&gt;When a workflow gets too manual, I spend more time operating tools than learning the system. Skaffold pushed me back toward learning the app itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  15. Important Commands Explained
&lt;/h2&gt;

&lt;p&gt;This is a compact cheat sheet for the commands I kept using.&lt;/p&gt;

&lt;h3&gt;
  
  
  kubectl commands
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kubectl get pods&lt;/code&gt;: shows Pods.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl get services&lt;/code&gt;: shows Services.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl get deployments&lt;/code&gt;: shows Deployments.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl describe pod&lt;/code&gt;: shows Pod events.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl logs&lt;/code&gt;: prints logs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl delete pod&lt;/code&gt;: removes a Pod.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl apply -f&lt;/code&gt;: applies YAML.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl delete -f&lt;/code&gt;: deletes YAML resources.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl rollout restart&lt;/code&gt;: restarts a Deployment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl exec&lt;/code&gt;: runs a command inside a container.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl port-forward&lt;/code&gt;: forwards a local port.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl get nodes&lt;/code&gt;: shows cluster nodes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl get ingress&lt;/code&gt;: shows Ingress resources.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl describe ingress&lt;/code&gt;: helps debug routing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f infra/k8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Minikube commands
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;minikube start&lt;/code&gt;: starts the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minikube stop&lt;/code&gt;: pauses the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minikube delete&lt;/code&gt;: resets the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minikube ip&lt;/code&gt;: prints the cluster IP.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minikube dashboard&lt;/code&gt;: opens the dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minikube docker-env&lt;/code&gt;: prints Docker settings.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;eval $(minikube docker-env)&lt;/code&gt;: points my shell at Minikube Docker.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Skaffold commands
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;skaffold dev&lt;/code&gt;: starts watch mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skaffold run&lt;/code&gt;: does one build and deploy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Docker commands
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docker build&lt;/code&gt;: creates an image.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker images&lt;/code&gt;: shows local images.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker ps&lt;/code&gt;: shows running containers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker logs&lt;/code&gt;: shows container output.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker exec&lt;/code&gt;: runs a command inside a container.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker tag&lt;/code&gt;: renames an image.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker push&lt;/code&gt;: uploads an image.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I knew these commands, I could move from confusion to inspection much faster.&lt;/p&gt;




&lt;h2&gt;
  
  
  16. Common Problems I Faced
&lt;/h2&gt;

&lt;p&gt;This project taught me that Kubernetes is full of small mistakes that look big at first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pods not starting
&lt;/h3&gt;

&lt;p&gt;Usually this happened because of an image issue, a bad manifest, or a port mismatch.&lt;/p&gt;

&lt;p&gt;How I debugged it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ran &lt;code&gt;kubectl get pods&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;used &lt;code&gt;kubectl describe pod&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;checked &lt;code&gt;kubectl logs&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ImagePullBackOff
&lt;/h3&gt;

&lt;p&gt;This often meant Kubernetes could not find the image.&lt;/p&gt;

&lt;p&gt;My fix was usually one of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build the image in Minikube Docker&lt;/li&gt;
&lt;li&gt;make sure the image name matches the manifest&lt;/li&gt;
&lt;li&gt;ensure the tag is correct&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CrashLoopBackOff
&lt;/h3&gt;

&lt;p&gt;This usually meant the container started and then crashed repeatedly.&lt;/p&gt;

&lt;p&gt;Common causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app error&lt;/li&gt;
&lt;li&gt;missing environment assumptions&lt;/li&gt;
&lt;li&gt;wrong port&lt;/li&gt;
&lt;li&gt;bad startup code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Service not found
&lt;/h3&gt;

&lt;p&gt;This usually meant I typed the wrong service name or expected the wrong DNS name.&lt;/p&gt;

&lt;p&gt;I learned to compare the service name in YAML with the one used in code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ingress not working
&lt;/h3&gt;

&lt;p&gt;This happened when the ingress controller was missing, the host file was wrong, or the route path did not match.&lt;/p&gt;

&lt;p&gt;I learned to check all three layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ingress resource exists&lt;/li&gt;
&lt;li&gt;ingress controller is running&lt;/li&gt;
&lt;li&gt;browser hostname resolves correctly&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Hosts file issues
&lt;/h3&gt;

&lt;p&gt;If the host mapping was wrong, nothing else mattered.&lt;/p&gt;

&lt;p&gt;That was a reminder that local networking issues can look like app issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Minikube IP changed
&lt;/h3&gt;

&lt;p&gt;When the Minikube IP changed, my hosts file mapping became stale.&lt;/p&gt;

&lt;p&gt;The fix was to run &lt;code&gt;minikube ip&lt;/code&gt; again and update the mapping.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker image not updating
&lt;/h3&gt;

&lt;p&gt;This happened when I changed code but the cluster kept using an old image.&lt;/p&gt;

&lt;p&gt;The fix was usually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rebuild the image&lt;/li&gt;
&lt;li&gt;use Skaffold&lt;/li&gt;
&lt;li&gt;verify Minikube Docker context&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Skaffold not rebuilding
&lt;/h3&gt;

&lt;p&gt;This usually meant the file sync rules were too narrow or the config did not match the file location.&lt;/p&gt;

&lt;p&gt;I learned to check the sync paths carefully.&lt;/p&gt;

&lt;h3&gt;
  
  
  My debugging habit
&lt;/h3&gt;

&lt;p&gt;The biggest lesson was not to guess.&lt;/p&gt;

&lt;p&gt;I tried to inspect one layer at a time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is the Pod running?&lt;/li&gt;
&lt;li&gt;Is the Service correct?&lt;/li&gt;
&lt;li&gt;Is the Ingress correct?&lt;/li&gt;
&lt;li&gt;Does the host file point to the right place?&lt;/li&gt;
&lt;li&gt;Does the app log show errors?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That simple checklist saved me a lot of time.&lt;/p&gt;




&lt;h2&gt;
  
  
  17. Pros and Cons
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pros of Kubernetes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It keeps services running and replaces failed Pods&lt;/li&gt;
&lt;li&gt;It supports service discovery&lt;/li&gt;
&lt;li&gt;It works from local dev to production&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons of Kubernetes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It has a steep learning curve&lt;/li&gt;
&lt;li&gt;YAML can be tedious&lt;/li&gt;
&lt;li&gt;Local setups can differ from production&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros of Skaffold
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It speeds up development&lt;/li&gt;
&lt;li&gt;It reduces manual commands&lt;/li&gt;
&lt;li&gt;It watches files and rebuilds automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons of Skaffold
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The config can be confusing at first&lt;/li&gt;
&lt;li&gt;Sync rules need care&lt;/li&gt;
&lt;li&gt;It adds another tool to learn&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros of Ingress
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;One entry point for many services&lt;/li&gt;
&lt;li&gt;Clean routing by host and path&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons of Ingress
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Needs an ingress controller&lt;/li&gt;
&lt;li&gt;Debugging can be tricky&lt;/li&gt;
&lt;li&gt;Host and path rules must match exactly&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros of Microservices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clear service boundaries&lt;/li&gt;
&lt;li&gt;Easier to scale parts separately&lt;/li&gt;
&lt;li&gt;Better for event-driven systems&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons of Microservices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;More moving parts&lt;/li&gt;
&lt;li&gt;More networking problems&lt;/li&gt;
&lt;li&gt;More concepts to learn&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  18. Lessons I Learned
&lt;/h2&gt;

&lt;p&gt;This is the part that matters most to me.&lt;/p&gt;

&lt;p&gt;At first, Kubernetes felt like too many objects with strange names. What helped was not reading more definitions. What helped was building something real.&lt;/p&gt;

&lt;p&gt;Once I saw the posts app create an event, then watched the query model update, then saw comments go through moderation, I started to understand why these parts exist.&lt;/p&gt;

&lt;p&gt;The biggest mental shift was this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker runs containers&lt;/li&gt;
&lt;li&gt;Kubernetes manages them&lt;/li&gt;
&lt;li&gt;Services make them reachable&lt;/li&gt;
&lt;li&gt;Ingress makes them public in a controlled way&lt;/li&gt;
&lt;li&gt;Skaffold makes development faster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also learned that microservices are not just about splitting code. They are about splitting responsibility.&lt;/p&gt;

&lt;p&gt;Another thing that became easier was reading YAML. At first it felt dry and repetitive, but later I saw it as a contract between me and Kubernetes.&lt;/p&gt;




&lt;h2&gt;
  
  
  19. Best Practices
&lt;/h2&gt;

&lt;p&gt;Here are the beginner-friendly practices that helped me most.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep services small
&lt;/h3&gt;

&lt;p&gt;Each service should have one clear job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use service names, not Pod IPs
&lt;/h3&gt;

&lt;p&gt;Pod IPs can change. Service names are stable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Separate write and read paths when it makes sense
&lt;/h3&gt;

&lt;p&gt;The CQRS idea helped my app stay organized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use ClusterIP for internal services
&lt;/h3&gt;

&lt;p&gt;Do not expose everything publicly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Ingress for the public entry point
&lt;/h3&gt;

&lt;p&gt;This keeps routing clean.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check logs early
&lt;/h3&gt;

&lt;p&gt;Logs often tell the truth faster than guesswork.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn the manifest one piece at a time
&lt;/h3&gt;

&lt;p&gt;Do not try to memorize everything at once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep your local environment clean
&lt;/h3&gt;

&lt;p&gt;If Minikube becomes messy, reset it instead of fighting stale state forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Skaffold during development
&lt;/h3&gt;

&lt;p&gt;It saves time and keeps the feedback loop short.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understand the path of a request
&lt;/h3&gt;

&lt;p&gt;Always ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where did the request start?&lt;/li&gt;
&lt;li&gt;Which service received it?&lt;/li&gt;
&lt;li&gt;Which Service forwarded it?&lt;/li&gt;
&lt;li&gt;Which Pod handled it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That question alone will save you a lot of confusion.&lt;/p&gt;




&lt;h2&gt;
  
  
  20. Conclusion
&lt;/h2&gt;

&lt;p&gt;I started this project wanting to learn Kubernetes. I ended up learning much more.&lt;/p&gt;

&lt;p&gt;I learned how containers package software.&lt;/p&gt;

&lt;p&gt;I learned how Kubernetes runs those containers across a cluster.&lt;/p&gt;

&lt;p&gt;I learned why Deployments matter, why Services matter, why Ingress matters, and why local tools like Minikube and Skaffold make practice possible.&lt;/p&gt;

&lt;p&gt;Most of all, I learned that Kubernetes becomes easier when it is tied to a real project.&lt;/p&gt;

&lt;p&gt;On their own, the concepts can feel abstract. But when I used them to run a real microservices app, they started to make sense.&lt;/p&gt;

&lt;p&gt;If you are a beginner, do not try to understand everything in one day. Build something small, break it, and repeat.&lt;/p&gt;

&lt;p&gt;That is how the pieces connect.&lt;/p&gt;




&lt;h2&gt;
  
  
  21. What’s Next?
&lt;/h2&gt;

&lt;p&gt;This project gave me a good base, but I know there is more to learn.&lt;/p&gt;

&lt;p&gt;The next topics I want to study are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ConfigMaps&lt;/li&gt;
&lt;li&gt;Secrets&lt;/li&gt;
&lt;li&gt;Persistent Volumes&lt;/li&gt;
&lt;li&gt;Helm&lt;/li&gt;
&lt;li&gt;Horizontal Pod Autoscaler&lt;/li&gt;
&lt;li&gt;Monitoring&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;CI/CD&lt;/li&gt;
&lt;li&gt;Production Kubernetes&lt;/li&gt;
&lt;li&gt;Cloud Kubernetes such as AWS EKS, GKE, and AKS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I feel more ready for those topics now because I understand the basics from a real app, not just from theory.&lt;/p&gt;




&lt;h2&gt;
  
  
  SEO Details
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SEO title
&lt;/h3&gt;

&lt;p&gt;Building a Microservices App with Kubernetes: My Beginner-Friendly Journey Through Docker, Minikube, Ingress, and Skaffold&lt;/p&gt;

&lt;h3&gt;
  
  
  Meta description
&lt;/h3&gt;

&lt;p&gt;A beginner-friendly story of building a microservices application with Kubernetes, covering Docker, Pods, Deployments, Services, Ingress, Minikube, Docker inside Minikube, and Skaffold in simple English.&lt;/p&gt;

&lt;h3&gt;
  
  
  Suggested URL slug
&lt;/h3&gt;

&lt;p&gt;building-microservices-app-with-kubernetes-docker-minikube-ingress-skaffold&lt;/p&gt;

&lt;h3&gt;
  
  
  Dev.to tags
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;kubernetes&lt;/li&gt;
&lt;li&gt;docker&lt;/li&gt;
&lt;li&gt;microservices&lt;/li&gt;
&lt;li&gt;devops&lt;/li&gt;
&lt;li&gt;beginners&lt;/li&gt;
&lt;li&gt;minikube&lt;/li&gt;
&lt;li&gt;skaffold&lt;/li&gt;
&lt;li&gt;ingress&lt;/li&gt;
&lt;li&gt;nodejs&lt;/li&gt;
&lt;li&gt;react&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Suggested cover image idea
&lt;/h3&gt;

&lt;p&gt;A clean illustration of a laptop connected to a Kubernetes cluster, with small boxes labeled Docker, Pods, Services, Ingress, and Skaffold, styled like a simple system map.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>kubernetes</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Kubernetes Internals Explained: From Linux Primitives to Ingress</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Tue, 07 Jul 2026 08:15:51 +0000</pubDate>
      <link>https://dev.to/m_toqeer/kubernetes-internals-explained-from-linux-primitives-to-ingress-21a5</link>
      <guid>https://dev.to/m_toqeer/kubernetes-internals-explained-from-linux-primitives-to-ingress-21a5</guid>
      <description>&lt;p&gt;If you've ever felt like Kubernetes is a pile of magic YAML files, this article is for you. We're going to build understanding from the ground up — starting with plain Linux, moving to containers, and then climbing all the way to Pods, Nodes, Deployments, Services, and Ingress. By the end, you won't just know the &lt;em&gt;names&lt;/em&gt; of these pieces — you'll know &lt;em&gt;why&lt;/em&gt; they exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Start With Linux?
&lt;/h2&gt;

&lt;p&gt;Kubernetes didn't invent containers. It's an &lt;strong&gt;orchestrator&lt;/strong&gt; sitting on top of Linux features that already existed. If you understand the Linux primitives first, every Kubernetes concept afterward becomes "oh, that's just automating this thing I already understand" instead of new magic to memorize.&lt;/p&gt;

&lt;p&gt;Two Linux kernel features make containers possible:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Namespaces — Isolation
&lt;/h3&gt;

&lt;p&gt;A namespace makes a process think it's the only thing running on the machine. Linux has several kinds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PID namespace&lt;/strong&gt; – the process sees itself as PID 1, even though the host sees it as PID 48213.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network namespace&lt;/strong&gt; – gives the process its own network interfaces, IP address, and routing table, separate from the host.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mount namespace&lt;/strong&gt; – gives the process its own view of the filesystem (its own &lt;code&gt;/&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UTS namespace&lt;/strong&gt; – lets the process have its own hostname.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IPC namespace&lt;/strong&gt; – isolates inter-process communication (shared memory, semaphores).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User namespace&lt;/strong&gt; – lets a process be "root" inside the container but be an unprivileged user on the host.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;strong&gt;container is just a regular Linux process&lt;/strong&gt; that has been put inside a bundle of these namespaces so it &lt;em&gt;believes&lt;/em&gt; it's alone on the machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Control Groups (cgroups) — Resource Limits
&lt;/h3&gt;

&lt;p&gt;Namespaces isolate &lt;em&gt;what a process can see&lt;/em&gt;. Cgroups control &lt;em&gt;how much it can use&lt;/em&gt; — CPU shares, memory limits, disk I/O, network bandwidth. This is how you can say "this container gets max 512Mi of RAM" and have the kernel actually enforce it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Container = Linux process + namespaces (isolation) + cgroups (resource limits) + a filesystem bundle (the image). Nothing more mystical than that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Container Images
&lt;/h2&gt;

&lt;p&gt;An image is a &lt;strong&gt;read-only template&lt;/strong&gt; for creating containers. It's built in &lt;strong&gt;layers&lt;/strong&gt; — each instruction in a Dockerfile (&lt;code&gt;FROM&lt;/code&gt;, &lt;code&gt;RUN&lt;/code&gt;, &lt;code&gt;COPY&lt;/code&gt;, etc.) creates a new layer stacked on top of the previous one using a union filesystem (like OverlayFS).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;Layer 4: COPY . /app          &amp;lt;- your app code
Layer 3: RUN npm install      &amp;lt;- dependencies
Layer 2: RUN apt-get update   &amp;lt;- OS packages
Layer 1: FROM node:20-alpine  &amp;lt;- base OS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why layers matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layers are &lt;strong&gt;cached&lt;/strong&gt; — if only your app code changes, Docker/containerd reuses the lower layers instead of rebuilding everything.&lt;/li&gt;
&lt;li&gt;Layers are &lt;strong&gt;shared&lt;/strong&gt; across images — ten images built &lt;code&gt;FROM node:20-alpine&lt;/code&gt; share that base layer on disk instead of duplicating it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Images live in &lt;strong&gt;registries&lt;/strong&gt; (Docker Hub, GitHub Container Registry, AWS ECR, etc.). When Kubernetes needs to run a container, it pulls the image from a registry to the Node first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Container Runtime
&lt;/h2&gt;

&lt;p&gt;This is the piece that actually &lt;strong&gt;takes an image and turns it into a running, namespaced, cgroup-limited process&lt;/strong&gt;. Kubernetes doesn't talk to Docker directly anymore — it talks through a standard interface called &lt;strong&gt;CRI (Container Runtime Interface)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The common runtime stack today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubelet
   │  (talks CRI protocol)
   ▼
containerd  (high-level runtime: manages images, pulls, storage)
   │
   ▼
runc  (low-level runtime: actually calls Linux syscalls to create
       namespaces/cgroups and start the process)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;runc&lt;/code&gt; is doing the literal work we described in the Linux section: calling &lt;code&gt;clone()&lt;/code&gt; with namespace flags, setting up cgroups, and &lt;code&gt;exec()&lt;/code&gt;-ing your process. Everything above it is orchestration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pods — The Smallest Deployable Unit
&lt;/h2&gt;

&lt;p&gt;Here's a question that trips people up: &lt;strong&gt;why doesn't Kubernetes just schedule containers directly?&lt;/strong&gt; Why the extra layer of a "Pod"?&lt;/p&gt;

&lt;p&gt;Answer: because real applications are often more than one process that need to share resources tightly — think of a main app container plus a logging sidecar that both need to read the same files and talk over &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Pod&lt;/strong&gt; is a group of one or more containers that share:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The same network namespace&lt;/strong&gt; — all containers in a Pod share one IP address and can reach each other over &lt;code&gt;localhost&lt;/code&gt;. Container A on port 8080 and container B on port 9090 in the same Pod just call &lt;code&gt;localhost:8080&lt;/code&gt; / &lt;code&gt;localhost:9090&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optionally, storage volumes&lt;/strong&gt; — a Pod can define a volume that multiple containers mount.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The same lifecycle&lt;/strong&gt; — they're scheduled together, and they die together.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How is the shared network namespace actually implemented? Kubernetes silently creates a hidden &lt;strong&gt;"pause" container&lt;/strong&gt; for every Pod. This container does nothing except hold open the network namespace. Every other container in the Pod joins &lt;em&gt;that&lt;/em&gt; namespace instead of creating its own. That's the real implementation detail behind "Pods share networking."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod (shares one network namespace + IP: 10.244.1.7)
├── pause container      (holds the namespace, does nothing)
├── app container        (localhost:8080)
└── sidecar container    (localhost:9090, e.g. log shipper)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is also why the Pod, not the container, is the atomic unit Kubernetes schedules, scales, and replaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nodes — Where Pods Actually Run
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Node&lt;/strong&gt; is a worker machine (VM or bare metal) running the components needed to host Pods. Every Node runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;kubelet&lt;/strong&gt; – the agent that talks to the control plane, receives instructions ("run this Pod"), and tells the container runtime to do it via CRI. It also continuously reports Pod health back up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;container runtime&lt;/strong&gt; – containerd + runc, as covered above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;kube-proxy&lt;/strong&gt; – maintains network rules on the Node (via &lt;code&gt;iptables&lt;/code&gt; or &lt;code&gt;IPVS&lt;/code&gt;) so that traffic sent to a Service IP gets routed to the correct backend Pod, even though the Pod could be on a completely different Node.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of the kubelet as a very obedient local supervisor: the control plane never SSHs into a Node to start something — it just updates a desired state, and kubelet on each Node notices and reconciles reality to match it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Control Plane — The Brain
&lt;/h2&gt;

&lt;p&gt;This is the part that decides &lt;em&gt;what should run where&lt;/em&gt;, and it's separate from the Nodes that actually run your workloads.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;kube-apiserver&lt;/strong&gt; – the front door. Every single interaction with the cluster — &lt;code&gt;kubectl&lt;/code&gt;, the scheduler, controllers, kubelets — goes through the API server. It validates requests and is the only component that talks directly to storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;etcd&lt;/strong&gt; – a distributed key-value store that holds the entire cluster state (every object, every desired configuration). If etcd is healthy, the cluster's "memory" is safe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;kube-scheduler&lt;/strong&gt; – watches for Pods with no Node assigned yet, and decides which Node they should run on, based on resource availability, affinity rules, taints/tolerations, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;kube-controller-manager&lt;/strong&gt; – runs the reconciliation loops. Example: the ReplicaSet controller constantly checks "do I have 3 Pods running as declared? If not, create more."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The core pattern to internalize:&lt;/strong&gt; you &lt;em&gt;declare&lt;/em&gt; desired state (via YAML → API server → etcd). Controllers continuously &lt;em&gt;watch&lt;/em&gt; for drift between desired state and actual state, and correct it. Kubernetes never "runs a command once" — it enforces a state forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployments
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Deployment&lt;/strong&gt; is a controller that manages &lt;strong&gt;ReplicaSets&lt;/strong&gt;, which in turn manage &lt;strong&gt;Pods&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deployment
   └── ReplicaSet (v1)
           ├── Pod
           ├── Pod
           └── Pod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why the extra ReplicaSet layer instead of Deployment managing Pods directly? &lt;strong&gt;Rolling updates.&lt;/strong&gt; When you update the image in a Deployment, it doesn't touch existing Pods — it creates a &lt;em&gt;new&lt;/em&gt; ReplicaSet with the new Pod template, scales it up gradually, and scales the old ReplicaSet down. This is how you get zero-downtime deploys and easy rollbacks (rolling back = pointing back at the old ReplicaSet).&lt;/p&gt;

&lt;h2&gt;
  
  
  Services — Solving the Pod IP Problem
&lt;/h2&gt;

&lt;p&gt;Pods are mortal. They get killed and recreated constantly (crashes, scaling, node failures) — and every time, they get a &lt;strong&gt;new IP address&lt;/strong&gt;. So how does anything reliably talk to "the backend"?&lt;/p&gt;

&lt;p&gt;This is what a &lt;strong&gt;Service&lt;/strong&gt; solves. A Service gets a &lt;strong&gt;stable virtual IP&lt;/strong&gt; and DNS name, and uses &lt;strong&gt;labels and selectors&lt;/strong&gt; to find which Pods should receive traffic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any Pod labeled &lt;code&gt;app: my-backend&lt;/code&gt; automatically becomes a backend for this Service — no matter how many times those Pods get replaced. kube-proxy on every Node maintains the routing rules that make "traffic to the Service IP" actually land on one of the healthy matching Pods.&lt;/p&gt;

&lt;p&gt;Three Service types matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ClusterIP&lt;/strong&gt; (default) – a virtual IP reachable &lt;em&gt;only from inside the cluster&lt;/em&gt;. Good for internal service-to-service communication (e.g., frontend Pod → backend Service).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NodePort&lt;/strong&gt; – opens a specific port (30000–32767 range) on &lt;em&gt;every&lt;/em&gt; Node's own IP, forwarding it into the Service. Lets external traffic in via &lt;code&gt;&amp;lt;NodeIP&amp;gt;:&amp;lt;NodePort&amp;gt;&lt;/code&gt;, but it's clunky for production (you're exposing raw node IPs and non-standard ports).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LoadBalancer&lt;/strong&gt; – asks the cloud provider (AWS/GCP/Azure) to provision an actual external load balancer that points at the Service. This is the standard way to expose something to the internet on a cloud cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Port Forwarding vs Services
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;kubectl port-forward pod/my-pod 8080:80&lt;/code&gt; is a &lt;strong&gt;developer debugging tool&lt;/strong&gt;, not a production traffic mechanism. It opens a temporary tunnel from your local machine straight to a single Pod, bypassing Services and kube-proxy entirely. The moment you kill that terminal, the connection is gone. It's for "let me poke this one Pod directly while debugging" — never how real traffic reaches your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ingress — HTTP Routing at the Edge
&lt;/h2&gt;

&lt;p&gt;If Services (specifically LoadBalancer) already expose things externally, why do we need Ingress too?&lt;/p&gt;

&lt;p&gt;Problem: if you have 10 HTTP microservices, giving each one its own cloud LoadBalancer means 10 expensive external load balancers, and no shared logic for things like TLS termination, host-based routing (&lt;code&gt;api.example.com&lt;/code&gt; vs &lt;code&gt;app.example.com&lt;/code&gt;), or path-based routing (&lt;code&gt;/users&lt;/code&gt; vs &lt;code&gt;/orders&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ingress&lt;/strong&gt; is a set of routing rules — "if the request comes in for &lt;code&gt;api.example.com/users&lt;/code&gt;, send it to the &lt;code&gt;users-service&lt;/code&gt; ClusterIP Service." But Ingress &lt;em&gt;rules alone do nothing&lt;/em&gt; — you need an &lt;strong&gt;Ingress Controller&lt;/strong&gt; (NGINX Ingress Controller, Traefik, etc.) running as Pods in your cluster that actually reads those rules and does the routing. The Ingress Controller is usually the one component that does get a single LoadBalancer Service, and everything else flows through it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
   │
   ▼
LoadBalancer Service (1 external IP)
   │
   ▼
Ingress Controller Pods (reads Ingress rules)
   │
   ├── /users  → users-service (ClusterIP)  → users Pods
   ├── /orders → orders-service (ClusterIP) → orders Pods
   └── api.example.com → api-service (ClusterIP) → api Pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Putting the Whole Request Path Together
&lt;/h2&gt;

&lt;p&gt;Here's the full journey of one HTTP request hitting your cluster, tying every piece above together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Request hits the &lt;strong&gt;cloud LoadBalancer&lt;/strong&gt;, which forwards to the &lt;strong&gt;Ingress Controller Pods&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Ingress Controller reads the &lt;strong&gt;Ingress rules&lt;/strong&gt; and decides which internal &lt;strong&gt;Service&lt;/strong&gt; should handle this path/host.&lt;/li&gt;
&lt;li&gt;It forwards the request to that Service's &lt;strong&gt;ClusterIP&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;kube-proxy&lt;/strong&gt;'s iptables/IPVS rules on the Node intercept traffic to that ClusterIP and redirect it to one of the matching &lt;strong&gt;Pods&lt;/strong&gt;, chosen via the Service's &lt;strong&gt;label selector&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Traffic lands inside the Pod's shared &lt;strong&gt;network namespace&lt;/strong&gt;, reaching the actual container process — a Linux process running inside namespaces and cgroups, started by &lt;strong&gt;runc&lt;/strong&gt;, pulled from an &lt;strong&gt;image&lt;/strong&gt; by &lt;strong&gt;containerd&lt;/strong&gt;, on instructions from the &lt;strong&gt;kubelet&lt;/strong&gt;, which got that instruction from the &lt;strong&gt;API server&lt;/strong&gt;, which persisted it from a &lt;strong&gt;Deployment&lt;/strong&gt; you applied, which is stored durably in &lt;strong&gt;etcd&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's the entire stack, front to back, in one sentence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;Every Kubernetes concept exists to solve a concrete problem:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Kubernetes Answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Isolate processes on Linux&lt;/td&gt;
&lt;td&gt;namespaces + cgroups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Package an app reproducibly&lt;/td&gt;
&lt;td&gt;container images&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actually run a container&lt;/td&gt;
&lt;td&gt;container runtime (containerd + runc)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Group tightly-coupled containers&lt;/td&gt;
&lt;td&gt;Pods&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run Pods somewhere&lt;/td&gt;
&lt;td&gt;Nodes (kubelet, kube-proxy, runtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decide cluster-wide state&lt;/td&gt;
&lt;td&gt;Control plane (API server, etcd, scheduler, controllers)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero-downtime updates &amp;amp; scaling&lt;/td&gt;
&lt;td&gt;Deployments + ReplicaSets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stable networking to mortal Pods&lt;/td&gt;
&lt;td&gt;Services + labels/selectors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Smart HTTP routing at the edge&lt;/td&gt;
&lt;td&gt;Ingress + Ingress Controller&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Once you see it this way, Kubernetes stops being "a huge list of YAML kinds to memorize" and becomes "a small number of real problems, each solved by one clean abstraction."&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If this helped clarify things, I'll be following up with a deeper dive into Services and networking internals (ClusterIP vs NodePort vs LoadBalancer under the hood) — let me know in the comments what you'd like covered next.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>kubernetes</category>
      <category>linux</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Database Sharding Explained: How to Scale Your Database Like a Pro</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Tue, 07 Jul 2026 07:27:48 +0000</pubDate>
      <link>https://dev.to/m_toqeer/database-sharding-explained-how-to-scale-your-database-like-a-pro-djc</link>
      <guid>https://dev.to/m_toqeer/database-sharding-explained-how-to-scale-your-database-like-a-pro-djc</guid>
      <description>&lt;p&gt;If you've ever worked on an application that grew from a handful of users to thousands—or millions—you've probably hit a point where your database starts groaning under the weight. Queries get slower. CPU spikes. Storage fills up. And no amount of indexing seems to fix it.&lt;/p&gt;

&lt;p&gt;This is usually where &lt;strong&gt;database sharding&lt;/strong&gt; enters the conversation.&lt;/p&gt;

&lt;p&gt;In this article, we'll break down what sharding actually is, why it matters, the most common strategies used in production systems, and how to decide if (and when) your project actually needs it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Database Sharding?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Database sharding&lt;/strong&gt; is a technique for splitting one large database into multiple smaller, independent databases called &lt;strong&gt;shards&lt;/strong&gt;. Each shard holds a portion of the total data, and together, all the shards make up the complete dataset.&lt;/p&gt;

&lt;p&gt;Think of it like a library system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A single library holding 10 million books becomes slow to search and hard to manage.&lt;/li&gt;
&lt;li&gt;So instead, the books get split across branches:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Branch A&lt;/strong&gt; → Books A–F&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branch B&lt;/strong&gt; → Books G–L&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branch C&lt;/strong&gt; → Books M–R&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branch D&lt;/strong&gt; → Books S–Z&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each branch only manages a fraction of the total collection, which makes browsing, searching, and organizing dramatically faster. Sharding applies this same idea to databases—except instead of book titles, we're splitting rows of data across servers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Do We Need Sharding?
&lt;/h2&gt;

&lt;p&gt;As an application scales, a single database server eventually runs into hard limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Slow query performance&lt;/li&gt;
&lt;li&gt; High CPU and memory usage&lt;/li&gt;
&lt;li&gt; Storage limitations&lt;/li&gt;
&lt;li&gt; Too many concurrent users/connections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sharding solves these problems by spreading data—and the load that comes with it—across multiple servers instead of forcing one machine to do all the work.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Practical Example
&lt;/h2&gt;

&lt;p&gt;Imagine you're running a social media platform with &lt;strong&gt;100 million users&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without sharding&lt;/strong&gt;, everything lives on one server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB Server 1
------------
User 1
User 2
User 3
...
User 100,000,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every read, write, and query hits this same machine. Eventually, it becomes a bottleneck no matter how much you optimize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With sharding&lt;/strong&gt;, the data is distributed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shard 1 → Users 1 – 25M
Shard 2 → Users 25M – 50M
Shard 3 → Users 50M – 75M
Shard 4 → Users 75M – 100M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now four servers share the load instead of one. Each shard only needs to handle a quarter of the traffic and storage.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Sharding Strategies
&lt;/h2&gt;

&lt;p&gt;There's no one-size-fits-all approach to sharding. Here are the three strategies you'll encounter most often.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Range-Based Sharding
&lt;/h3&gt;

&lt;p&gt;Data is split according to a defined range of values (like ID ranges).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shard 1 → User IDs 1–1000
Shard 2 → User IDs 1001–2000
Shard 3 → User IDs 2001–3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Query example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application already knows this record lives in &lt;strong&gt;Shard 2&lt;/strong&gt;, so it routes the query there directly.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Simple to understand and implement&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Uneven growth can cause "hot" shards—one shard may end up much larger or busier than the others&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Hash-Based Sharding
&lt;/h3&gt;

&lt;p&gt;A hash function decides which shard a piece of data belongs to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;shard = userId % 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example distribution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 % 3 = 1 → Shard 1
2 % 3 = 2 → Shard 2
3 % 3 = 0 → Shard 3
4 % 3 = 1 → Shard 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Distributes data evenly across shards, avoiding hotspots&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Adding or removing shards later is difficult, since it changes the hash math and can require re-shuffling large amounts of data (this is where consistent hashing usually comes in to soften the blow)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Geographic Sharding
&lt;/h3&gt;

&lt;p&gt;Data is partitioned based on the user's region or location.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shard Pakistan → Pakistani users
Shard USA      → American users
Shard Europe   → European users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is common in global applications, since it also helps reduce latency (users are served from a shard closer to them) and can assist with data residency/compliance requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Does the Application Know Which Shard to Use?
&lt;/h2&gt;

&lt;p&gt;This is handled through a &lt;strong&gt;shard key&lt;/strong&gt;—a value used to determine where a specific piece of data lives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the shard is calculated, the application routes the query to the correct database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shard&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DB1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shard&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DB2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// ...and so on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In real-world systems, this routing logic is often abstracted into a middleware layer or handled by the database driver/proxy itself, so individual services don't need to reimplement it everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-Life Example: E-Commerce Platform
&lt;/h2&gt;

&lt;p&gt;Let's say you're building an e-commerce platform and want to shard your &lt;code&gt;users&lt;/code&gt; table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User ID
--------
1
2
3
4
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Sharding strategy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shard 1 → User IDs ending in 0–4
Shard 2 → User IDs ending in 5–9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;strong&gt;User 1234&lt;/strong&gt; logs in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1234 % 2 = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request is routed to &lt;strong&gt;Shard 1&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sharding vs. Replication: What's the Difference?
&lt;/h2&gt;

&lt;p&gt;People often confuse sharding with replication, but they solve different problems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sharding&lt;/th&gt;
&lt;th&gt;Replication&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Splits data across servers&lt;/td&gt;
&lt;td&gt;Copies the same data to multiple servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Used for scaling &lt;strong&gt;writes&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Used for scaling &lt;strong&gt;reads&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Each shard holds different data&lt;/td&gt;
&lt;td&gt;Every replica holds the same data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increases storage capacity&lt;/td&gt;
&lt;td&gt;Improves availability &amp;amp; redundancy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Sharding example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB1 → Users 1–1000
DB2 → Users 1001–2000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Replication example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      Primary DB
          |
   +------+------+
   |             |
Replica 1     Replica 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In many production systems, these two techniques are actually combined—each shard has its own set of replicas for both scalability &lt;em&gt;and&lt;/em&gt; availability.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interview-Ready Summary
&lt;/h2&gt;

&lt;p&gt;If you're prepping for a system design interview, here's a concise way to explain it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Database sharding is a horizontal scaling technique where data is partitioned across multiple database servers called shards. Each shard contains a subset of the data and handles part of the application's workload. Sharding improves scalability, performance, and storage capacity for large-scale systems. Common strategies include range-based, hash-based, and geographic sharding.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  When Should You Actually Use Sharding?
&lt;/h2&gt;

&lt;p&gt;Sharding is powerful, but it's not something you should reach for on day one. It adds real architectural complexity—cross-shard queries, distributed transactions, and rebalancing all become harder problems once you shard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consider sharding when:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your database size is becoming too large for a single server&lt;br&gt;
 Write traffic is very high&lt;br&gt;
 Queries are slowing down despite indexing and optimization&lt;br&gt;
 Vertical scaling (more CPU/RAM) is no longer enough&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before reaching for sharding, try:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query optimization&lt;/li&gt;
&lt;li&gt;Better indexing&lt;/li&gt;
&lt;li&gt;Caching layers (Redis, Memcached, etc.)&lt;/li&gt;
&lt;li&gt;Read replicas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sharding is typically introduced once an application reaches a large scale—think millions of users or datasets that no longer fit comfortably on one machine. Until then, simpler scaling techniques usually get you further with far less complexity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Sharding is one of those concepts that sounds intimidating until you break it down—at its core, it's just "divide the data so no single server has to do all the work." The real challenge isn't understanding the concept, it's choosing the right shard key and strategy for your specific access patterns, and being ready for the operational complexity that comes with a distributed database layer.&lt;/p&gt;

&lt;p&gt;If you're designing for scale, start simple, measure where your actual bottlenecks are, and only shard when you have clear evidence that you need to.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this helpful, feel free to follow for more system design breakdowns!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>database</category>
      <category>distributedsystems</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>JavaScript Under the Hood: Scope, Closures, Prototypes &amp;</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Mon, 29 Jun 2026 18:02:21 +0000</pubDate>
      <link>https://dev.to/m_toqeer/javascript-under-the-hood-scope-closures-prototypes--48o3</link>
      <guid>https://dev.to/m_toqeer/javascript-under-the-hood-scope-closures-prototypes--48o3</guid>
      <description>&lt;p&gt;&lt;em&gt;A deep dive into the concepts that separate junior devs from engineers who actually understand the runtime.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Scope and Closures
&lt;/h2&gt;

&lt;h3&gt;
  
  
  var vs let vs const — It's Not Just Syntax
&lt;/h3&gt;

&lt;p&gt;Most devs learn early that &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; are "the modern way" and &lt;code&gt;var&lt;/code&gt; is old. But the real difference runs deeper than style.&lt;/p&gt;

&lt;h4&gt;
  
  
  Hoisting
&lt;/h4&gt;

&lt;p&gt;JavaScript hoists declarations to the top of their scope before execution. But how that hoisting behaves depends on which keyword you use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// undefined (not an error!)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Toqeer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ReferenceError: Cannot access 'age' before initialization&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;var&lt;/code&gt; is hoisted &lt;strong&gt;and initialized&lt;/strong&gt; to &lt;code&gt;undefined&lt;/code&gt;. So the engine sees this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// hoisted to top&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// undefined&lt;/span&gt;
&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Toqeer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; are also hoisted — but they are &lt;strong&gt;not initialized&lt;/strong&gt;. They exist in what's called the &lt;strong&gt;Temporal Dead Zone (TDZ)&lt;/strong&gt; from the start of the block until the declaration is reached.&lt;/p&gt;

&lt;h4&gt;
  
  
  Temporal Dead Zone (TDZ)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// TDZ for `score` starts here&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ReferenceError&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// TDZ ends here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable exists in the scope, the engine knows about it — but you cannot touch it yet. This is intentional. It prevents you from accidentally using a variable before it's ready.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;const&lt;/code&gt;&lt;/strong&gt; adds one more layer: once assigned, the binding cannot be reassigned. For objects and arrays, the reference is locked — but the contents can still mutate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// fine&lt;/span&gt;
&lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;         &lt;span class="c1"&gt;// TypeError: Assignment to constant variable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Scope: Function vs Block
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;var&lt;/code&gt; is &lt;strong&gt;function-scoped&lt;/strong&gt;. It leaks out of blocks like &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "active" — leaked out of the if block&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; are &lt;strong&gt;block-scoped&lt;/strong&gt;. They stay inside &lt;code&gt;{}&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ReferenceError&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why the classic loop bug exists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Prints: 3, 3, 3&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Prints: 0, 1, 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;var&lt;/code&gt;, there's only one &lt;code&gt;i&lt;/code&gt; shared across all iterations. With &lt;code&gt;let&lt;/code&gt;, each iteration gets its own block-scoped &lt;code&gt;i&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Closures: One of JavaScript's Superpowers
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;closure&lt;/strong&gt; is a function that remembers the variables from its outer scope — even after that outer scope has finished executing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeCounter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;makeCounter&lt;/code&gt; has long since returned. Its execution context is gone. But &lt;code&gt;count&lt;/code&gt; lives on — because the inner function &lt;strong&gt;closed over&lt;/strong&gt; it.&lt;/p&gt;

&lt;h4&gt;
  
  
  How Closures Form
&lt;/h4&gt;

&lt;p&gt;A closure forms every time a function is created inside another function and references variables from the outer scope. The inner function holds a &lt;strong&gt;reference&lt;/strong&gt; to the outer environment, not a copy.&lt;/p&gt;

&lt;h4&gt;
  
  
  Practical Uses
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1. Data privacy / encapsulation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createBankAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialBalance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialBalance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createBankAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 1500&lt;/span&gt;
&lt;span class="c1"&gt;// `balance` is not accessible from outside&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Function factories:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;triple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;triple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Memoization:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factorial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  IIFE — Immediately Invoked Function Expression
&lt;/h3&gt;

&lt;p&gt;An IIFE is a function that runs the moment it's defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Runs immediately&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="c1"&gt;// `secret` is not accessible out here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The outer &lt;code&gt;()&lt;/code&gt; wraps the function expression (makes it an expression, not a declaration), and the trailing &lt;code&gt;()&lt;/code&gt; invokes it immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why use it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before ES modules and block scoping with &lt;code&gt;let&lt;/code&gt;/&lt;code&gt;const&lt;/code&gt;, IIFEs were the primary way to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a private scope and avoid polluting the global namespace&lt;/li&gt;
&lt;li&gt;Initialize libraries and plugins&lt;/li&gt;
&lt;li&gt;Wrap module code
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;_privateState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;_privateState&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;_privateState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Today, ES modules handle this naturally. But IIFEs still appear in bundled output and are worth understanding.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Prototypes and Inheritance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Prototype Chain
&lt;/h3&gt;

&lt;p&gt;JavaScript is a &lt;strong&gt;prototype-based&lt;/strong&gt; language. Every object has an internal link — &lt;code&gt;[[Prototype]]&lt;/code&gt; — that points to another object. When you access a property, JavaScript first looks on the object itself, then walks up the chain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;breathe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;breathing...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;woof!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;    &lt;span class="c1"&gt;// "woof!" — found on dog&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;breathe&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "breathing..." — found on animal (via prototype)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// found on Object.prototype&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The chain: &lt;code&gt;dog&lt;/code&gt; → &lt;code&gt;animal&lt;/code&gt; → &lt;code&gt;Object.prototype&lt;/code&gt; → &lt;code&gt;null&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When the end (&lt;code&gt;null&lt;/code&gt;) is reached without finding the property, &lt;code&gt;undefined&lt;/code&gt; is returned (or a &lt;code&gt;TypeError&lt;/code&gt; for method calls).&lt;/p&gt;

&lt;h3&gt;
  
  
  Object.create and Object.getPrototypeOf
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Object.create(proto)&lt;/code&gt; creates a new object whose prototype is &lt;code&gt;proto&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vehicleProto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`I am a &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; with &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wheels&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; wheels`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;car&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vehicleProto&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;car&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;car&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;car&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wheels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;car&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "I am a car with 4 wheels"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Object.getPrototypeOf(obj)&lt;/code&gt; lets you inspect the chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPrototypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;car&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;vehicleProto&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Constructor Functions
&lt;/h3&gt;

&lt;p&gt;Before ES6 classes, constructor functions were the way to create objects with shared behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Hi, I'm &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toqeer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Toqeer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toqeer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "Hi, I'm Toqeer"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;greet&lt;/code&gt; lives on &lt;code&gt;Person.prototype&lt;/code&gt;, not on each instance — so all instances share it without duplication.&lt;/p&gt;




&lt;h3&gt;
  
  
  The &lt;code&gt;new&lt;/code&gt; Keyword — What Actually Happens
&lt;/h3&gt;

&lt;p&gt;When you call a function with &lt;code&gt;new&lt;/code&gt;, four things happen under the hood:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. A new empty object is created: {}
2. Its [[Prototype]] is linked to Constructor.prototype
3. `this` inside the function points to that new object
4. The function returns `this` (the new object) unless it explicitly returns another object
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see this manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;myNew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Constructor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// step 1 &amp;amp; 2&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// step 3&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// step 4&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;myNew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Toqeer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "Hi, I'm Toqeer"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is exactly what &lt;code&gt;new&lt;/code&gt; does — now it's not magic.&lt;/p&gt;




&lt;h3&gt;
  
  
  ES6 Classes — Syntactic Sugar
&lt;/h3&gt;

&lt;p&gt;Classes in JavaScript are not a new object model. They're a cleaner syntax over the same prototype mechanism.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; makes a sound.`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; barks.`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "Rex barks."&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Animal&lt;/code&gt; is a constructor function&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;speak&lt;/code&gt; is added to &lt;code&gt;Animal.prototype&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;extends&lt;/code&gt; sets up the prototype chain: &lt;code&gt;Dog.prototype → Animal.prototype&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;super()&lt;/code&gt; calls the parent constructor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output is identical to doing it manually with constructor functions and &lt;code&gt;Object.create&lt;/code&gt;. Classes just make the intent clearer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Differences from Constructor Functions
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Constructor Function&lt;/th&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hoisted&lt;/td&gt;
&lt;td&gt;Yes (as &lt;code&gt;undefined&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;No (TDZ applies)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strict mode&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;Always strict&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Callable without &lt;code&gt;new&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Yes (bad idea)&lt;/td&gt;
&lt;td&gt;TypeError&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inherited methods&lt;/td&gt;
&lt;td&gt;Manual prototype chain&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;extends&lt;/code&gt; keyword&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;super&lt;/code&gt; call&lt;/td&gt;
&lt;td&gt;Manual with &lt;code&gt;.call&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Putting It All Together
&lt;/h3&gt;

&lt;p&gt;Here's everything combined — a real-world-ish example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EventEmitter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;listeners&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// for chaining&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Store&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;EventEmitter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;State changed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// "State changed: { count: 1 }"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private class fields (&lt;code&gt;#listeners&lt;/code&gt;, &lt;code&gt;#state&lt;/code&gt;) for encapsulation — closure-like privacy at the class level&lt;/li&gt;
&lt;li&gt;Prototype inheritance via &lt;code&gt;extends&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;super()&lt;/code&gt; to call the parent constructor&lt;/li&gt;
&lt;li&gt;Method chaining via &lt;code&gt;return this&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scoping Rules
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;var&lt;/code&gt; → function-scoped, hoisted and initialized to &lt;code&gt;undefined&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;let&lt;/code&gt; / &lt;code&gt;const&lt;/code&gt; → block-scoped, hoisted but in TDZ until declaration&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;const&lt;/code&gt; → block-scoped + immutable binding (contents can mutate)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Closures
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Form when an inner function references outer variables&lt;/li&gt;
&lt;li&gt;The inner function holds a reference to the outer environment, not a copy&lt;/li&gt;
&lt;li&gt;Useful for: encapsulation, factories, memoization, event handlers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  IIFE
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Runs immediately, creates isolated scope&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(function() { ... })()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Less common today due to ES modules, but still found in bundled code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prototype Chain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Every object has a &lt;code&gt;[[Prototype]]&lt;/code&gt; link&lt;/li&gt;
&lt;li&gt;Property lookup walks the chain until &lt;code&gt;null&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Object.create(proto)&lt;/code&gt; sets the prototype explicitly&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;new&lt;/code&gt; Keyword Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create empty object&lt;/li&gt;
&lt;li&gt;Link prototype to &lt;code&gt;Constructor.prototype&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Execute constructor with &lt;code&gt;this&lt;/code&gt; = new object&lt;/li&gt;
&lt;li&gt;Return the new object (unless constructor returns an object)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Classes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Syntactic sugar over prototypes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;extends&lt;/code&gt; wires prototype chain&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;super()&lt;/code&gt; calls parent constructor&lt;/li&gt;
&lt;li&gt;Always strict, not hoistable&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Understanding these fundamentals will make you a better debugger, a better code reviewer, and a more confident engineer — whether you're writing Node.js APIs, React apps, or contributing to open source.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drop a comment if you want me to go deeper on any of these. Happy to cover the event loop, async/await internals, or WeakMaps and memory management next.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Fine-Tuning Large Language Models: A Practical Guide</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Tue, 16 Jun 2026 08:59:56 +0000</pubDate>
      <link>https://dev.to/m_toqeer/fine-tuning-large-language-models-a-practical-guide-7b9</link>
      <guid>https://dev.to/m_toqeer/fine-tuning-large-language-models-a-practical-guide-7b9</guid>
      <description>&lt;h2&gt;
  
  
  What Is Fine-Tuning?
&lt;/h2&gt;

&lt;p&gt;A pre-trained model learns from billions of tokens of general text. It develops broad language understanding. Fine-tuning takes that base model and trains it further on a smaller, task-specific dataset.&lt;/p&gt;

&lt;p&gt;The result: a model that performs well on your specific use case, whether that is medical diagnosis, legal summarization, customer support, or code generation.&lt;/p&gt;

&lt;p&gt;Fine-tuning is not training from scratch. You preserve general knowledge and adapt behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  How a Neural Network Learns
&lt;/h2&gt;

&lt;p&gt;Before fine-tuning makes sense, you need to understand what happens inside a neural network during training.&lt;/p&gt;

&lt;p&gt;A neural network is a system of layers. Each layer contains nodes (neurons). Each connection between nodes has a weight. These weights determine what the network outputs given any input.&lt;/p&gt;

&lt;p&gt;At the start, weights are random. Training adjusts them so the network produces correct outputs.&lt;/p&gt;

&lt;p&gt;Here is the full training loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Training Data
      ↓
Forward Pass
      ↓
Prediction
      ↓
Loss Calculation
      ↓
Backpropagation
      ↓
Gradient Calculation
      ↓
Weight Update
      ↓
Repeat
      ↓
Trained Model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Phase 1: Forward Pass
&lt;/h3&gt;

&lt;p&gt;The model receives an input (a sentence, an image, a token). Data flows forward through every layer. Each neuron applies a mathematical function and passes its result to the next layer.&lt;/p&gt;

&lt;p&gt;At the end, the model produces a prediction. For a language model, this is a probability distribution over the next token.&lt;/p&gt;

&lt;p&gt;No learning happens here. This phase only produces output.&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 2: Loss Calculation
&lt;/h3&gt;

&lt;p&gt;The model's prediction is compared to the correct answer. A loss function measures how wrong the prediction is.&lt;/p&gt;

&lt;p&gt;Common loss functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cross-entropy loss: used for classification and language modeling&lt;/li&gt;
&lt;li&gt;Mean squared error: used for regression tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A high loss means the model is far off. A loss near zero means the prediction was close to correct.&lt;/p&gt;

&lt;p&gt;The loss is a single number. It summarizes the error for one batch of data.&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 3: Backpropagation
&lt;/h3&gt;

&lt;p&gt;This is where learning begins.&lt;/p&gt;

&lt;p&gt;Backpropagation works backward through the network. It calculates how much each weight contributed to the total loss. The math tool used here is the chain rule from calculus.&lt;/p&gt;

&lt;p&gt;Think of it as blame assignment. Each weight receives a gradient: a number that says "changing this weight by X changes the loss by Y."&lt;/p&gt;

&lt;p&gt;A large gradient means that weight had a big effect on the error. A small gradient means it had little effect.&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 4: Gradient Calculation
&lt;/h3&gt;

&lt;p&gt;After backpropagation, every weight in the network has a gradient.&lt;/p&gt;

&lt;p&gt;The gradient is a vector. It points in the direction of steepest increase in loss. To reduce the loss, you move in the opposite direction.&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 5: Weight Update (Optimization)
&lt;/h3&gt;

&lt;p&gt;An optimizer uses the gradients to update every weight.&lt;/p&gt;

&lt;p&gt;The most basic optimizer is Stochastic Gradient Descent (SGD):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;new_weight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;old_weight&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;learning_rate&lt;/span&gt; &lt;span class="err"&gt;×&lt;/span&gt; &lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The learning rate controls the step size. Too large: the model overshoots. Too small: training takes too long.&lt;/p&gt;

&lt;p&gt;Modern optimizers like Adam adjust the learning rate automatically for each weight. Adam tracks the history of gradients and adapts accordingly. It converges faster than basic SGD in most cases.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Full Loop
&lt;/h3&gt;

&lt;p&gt;One pass through the data is one epoch. Training repeats this loop thousands of times across many epochs. With each pass, the weights improve. The loss decreases. The model gets better at the task.&lt;/p&gt;




&lt;h2&gt;
  
  
  Types of Fine-Tuning
&lt;/h2&gt;

&lt;p&gt;There are three main approaches. They differ in what gets updated during training.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Full Fine-Tuning
&lt;/h3&gt;

&lt;p&gt;All weights in the model are updated.&lt;/p&gt;

&lt;p&gt;You take the pre-trained model and run the training loop on your dataset. Every parameter is fair game. The optimizer adjusts all of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maximum flexibility&lt;/li&gt;
&lt;li&gt;Best performance ceiling for large datasets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires significant GPU memory (storing the model, gradients, and optimizer states for billions of parameters)&lt;/li&gt;
&lt;li&gt;Expensive and slow&lt;/li&gt;
&lt;li&gt;Risk of catastrophic forgetting: the model overwrites general knowledge with task-specific patterns&lt;/li&gt;
&lt;li&gt;A 7B parameter model at full precision requires roughly 28 GB of GPU memory for weights alone, plus optimizer states&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full fine-tuning makes sense when you have large datasets and substantial compute.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. PEFT (Parameter-Efficient Fine-Tuning)
&lt;/h3&gt;

&lt;p&gt;PEFT is a family of methods. The core idea: freeze most of the model and only train a small number of parameters.&lt;/p&gt;

&lt;p&gt;You add new, trainable components to the frozen model. Only those new components are updated. The original weights stay fixed.&lt;/p&gt;

&lt;p&gt;This reduces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GPU memory required (no gradients for frozen weights)&lt;/li&gt;
&lt;li&gt;Training time&lt;/li&gt;
&lt;li&gt;Risk of catastrophic forgetting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PEFT methods include LoRA, prefix tuning, prompt tuning, and adapter layers. LoRA is the most widely used.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. LoRA (Low-Rank Adaptation)
&lt;/h3&gt;

&lt;p&gt;LoRA is the dominant PEFT method in 2024 and 2025.&lt;/p&gt;

&lt;p&gt;The insight behind LoRA: weight updates during fine-tuning tend to have low intrinsic rank. You do not need to update a full weight matrix. You approximate the update with two much smaller matrices.&lt;/p&gt;

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

&lt;p&gt;For a weight matrix W of size (m × n), instead of updating W directly, LoRA adds two matrices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Matrix A: size (m × r)&lt;/li&gt;
&lt;li&gt;Matrix B: size (r × n)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where r is the rank, typically 4, 8, 16, or 64. You only train A and B. The product AB approximates the full weight update.&lt;/p&gt;

&lt;p&gt;During inference, the update is merged back: W_new = W + AB&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameter count comparison:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A weight matrix of size 4096 × 4096 has 16,777,216 parameters.&lt;br&gt;
LoRA with rank 8 adds two matrices: (4096 × 8) + (8 × 4096) = 65,536 parameters.&lt;br&gt;
That is a 256x reduction in trainable parameters for that layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trains on consumer GPUs (a 7B model with LoRA fits on 8-16 GB VRAM)&lt;/li&gt;
&lt;li&gt;Multiple LoRA adapters for different tasks, swapped at inference time&lt;/li&gt;
&lt;li&gt;The base model stays frozen and reusable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slightly below full fine-tuning on performance in some benchmarks&lt;/li&gt;
&lt;li&gt;Requires choosing rank (r) and which layers to target&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. QLoRA (Quantized LoRA)
&lt;/h3&gt;

&lt;p&gt;QLoRA combines quantization with LoRA. It pushes LoRA further in terms of memory efficiency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What quantization does:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Standard model weights use 16-bit or 32-bit floating point numbers. Quantization converts them to lower precision: 8-bit, 4-bit, or even 3-bit integers.&lt;/p&gt;

&lt;p&gt;A 7B model in 16-bit uses roughly 14 GB of memory. The same model in 4-bit uses roughly 3.5 GB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QLoRA workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load the base model in 4-bit precision (NF4 format, designed for neural network weights)&lt;/li&gt;
&lt;li&gt;Freeze all quantized weights&lt;/li&gt;
&lt;li&gt;Add LoRA adapters in 16-bit precision&lt;/li&gt;
&lt;li&gt;Train only the LoRA adapters&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The gradients flow through the quantized model, through the LoRA adapters. Only the adapters are updated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Double quantization:&lt;/strong&gt; QLoRA applies a second round of quantization to the quantization constants themselves, saving an additional 0.5 GB on a 7B model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fine-tune a 70B model on a single 48 GB GPU&lt;/li&gt;
&lt;li&gt;Fine-tune a 7B model on a single 8 GB consumer GPU&lt;/li&gt;
&lt;li&gt;Performance within 1-2% of full fine-tuning on most benchmarks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slower than LoRA (dequantization overhead during forward/backward pass)&lt;/li&gt;
&lt;li&gt;Quantization introduces approximation errors&lt;/li&gt;
&lt;/ul&gt;




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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Trainable Params&lt;/th&gt;
&lt;th&gt;VRAM (7B model)&lt;/th&gt;
&lt;th&gt;Performance&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Full Fine-Tuning&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;80+ GB&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;Large datasets, max compute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PEFT (general)&lt;/td&gt;
&lt;td&gt;0.1 - 1%&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Resource-constrained&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LoRA&lt;/td&gt;
&lt;td&gt;0.1 - 1%&lt;/td&gt;
&lt;td&gt;16-24 GB&lt;/td&gt;
&lt;td&gt;Near full&lt;/td&gt;
&lt;td&gt;Most fine-tuning tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;QLoRA&lt;/td&gt;
&lt;td&gt;0.1 - 1%&lt;/td&gt;
&lt;td&gt;6-10 GB&lt;/td&gt;
&lt;td&gt;Near LoRA&lt;/td&gt;
&lt;td&gt;Consumer GPU fine-tuning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Choosing the Right Method
&lt;/h2&gt;

&lt;p&gt;Start with QLoRA if you are on a single GPU with less than 24 GB VRAM. It lets you work with models up to 13B or 30B parameters.&lt;/p&gt;

&lt;p&gt;Use LoRA if you have 24-40 GB VRAM and want faster training than QLoRA.&lt;/p&gt;

&lt;p&gt;Use full fine-tuning if you have a multi-GPU setup, a large high-quality dataset (100k+ samples), and need maximum task performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Hyperparameters in Fine-Tuning
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Learning rate:&lt;/strong&gt; Typically much lower for fine-tuning than pre-training. Common range: 1e-5 to 3e-4. Too high and you destroy pre-trained representations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rank (r) in LoRA:&lt;/strong&gt; Higher rank captures more complex updates but uses more memory. Start with 8 or 16.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LoRA alpha:&lt;/strong&gt; Scales the LoRA update. Common setting: alpha = 2 × rank.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Epochs:&lt;/strong&gt; Fine-tuning usually needs far fewer epochs than pre-training. 1 to 5 epochs on domain-specific data is typical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch size:&lt;/strong&gt; Larger batches give smoother gradients. Use gradient accumulation if your GPU limits batch size.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes Good Fine-Tuning Data
&lt;/h2&gt;

&lt;p&gt;Data quality matters more than quantity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,000 high-quality examples often outperform 100,000 noisy ones&lt;/li&gt;
&lt;li&gt;Format your data to match the task: instruction-response pairs for chat models, completions for base models&lt;/li&gt;
&lt;li&gt;Balance your dataset across categories to avoid the model over-indexing on one topic&lt;/li&gt;
&lt;li&gt;Remove duplicates; they waste training compute and bias the model&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Neural networks learn by repeating a loop: forward pass, loss calculation, backpropagation, gradient calculation, weight update. Fine-tuning runs this loop on task-specific data starting from a pre-trained model.&lt;/p&gt;

&lt;p&gt;Full fine-tuning updates everything. PEFT methods freeze most weights. LoRA approximates weight updates with low-rank matrices. QLoRA adds quantization to push memory requirements lower.&lt;/p&gt;

&lt;p&gt;Your choice depends on your GPU, your dataset size, and your performance target.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>machinelearning</category>
      <category>nlp</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What I Learned Building an Autonomous Deal-Hunting Agent System</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Mon, 15 Jun 2026 11:41:48 +0000</pubDate>
      <link>https://dev.to/m_toqeer/what-i-learned-building-an-autonomous-deal-hunting-agent-system-3n6b</link>
      <guid>https://dev.to/m_toqeer/what-i-learned-building-an-autonomous-deal-hunting-agent-system-3n6b</guid>
      <description>&lt;p&gt;Over the past week I built a multi-agent AI system that autonomously scans the internet for bargains, estimates the &lt;em&gt;true&lt;/em&gt; value of products using three different pricing techniques, and pushes a notification straight to my phone the moment it finds a deal worth acting on. Along the way I picked up a ton of practical, transferable lessons about agentic AI architecture, RAG, fine-tuning vs. prompting, tool calling, and shipping a real (if scrappy) product with a Gradio front end.&lt;/p&gt;

&lt;p&gt;This post is my write-up of the whole journey, with the code that made it work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Picture: A Team of Specialist Agents
&lt;/h2&gt;

&lt;p&gt;The system, nicknamed &lt;strong&gt;"The Price Is Right"&lt;/strong&gt;, is built around the idea that no single model is the best at everything. Instead of one giant prompt, the architecture splits the problem into focused agents that each do one job well, coordinated by a planning agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scanner Agent&lt;/strong&gt; – trawls deal RSS feeds and uses a cheap LLM to pick the 5 most promising, well-described deals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specialist Agent&lt;/strong&gt; – a small open-source model (Llama 3.2) that I fine-tuned specifically to estimate product prices, deployed serverlessly on Modal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontier Agent&lt;/strong&gt; – a frontier model (GPT-5.1) doing price estimation with RAG, pulling similar products from a vector database for context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensemble Agent&lt;/strong&gt; – combines the Specialist, Frontier, and a classic neural network into a single weighted estimate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Messaging Agent&lt;/strong&gt; – sends a push notification to my phone via Pushover when a great deal is found.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous Planning Agent&lt;/strong&gt; – the "brain" that ties everything together using function/tool calling, deciding what to scan, what to estimate, and when to notify.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deal Agent Framework&lt;/strong&gt; – the orchestration layer that runs the whole loop and persists memory between runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradio UI&lt;/strong&gt; – a live dashboard showing deals as they're discovered, plus a 3D visualization of the underlying product vector store.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's how the five days of building this broke down.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 1: Deploying Models to the Cloud with Modal
&lt;/h2&gt;

&lt;p&gt;The first lesson was about &lt;strong&gt;infrastructure&lt;/strong&gt;: how do you run a model (especially a fine-tuned open-source LLM) without managing your own GPU server? The answer here was &lt;a href="https://modal.com" rel="noopener noreferrer"&gt;Modal&lt;/a&gt;, a serverless platform for running Python functions in the cloud — including on GPUs.&lt;/p&gt;

&lt;p&gt;The "hello world" of Modal is refreshingly simple. You define an &lt;code&gt;App&lt;/code&gt;, an &lt;code&gt;Image&lt;/code&gt; (essentially a container spec with pip dependencies), and decorate a normal Python function with &lt;code&gt;@app.function&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# hello.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;

&lt;span class="c1"&gt;# Setup
&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debian_slim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pip_install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;requests&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Hello!
&lt;/span&gt;

&lt;span class="nd"&gt;@app.function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://ipinfo.io/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;country&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello from &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="c1"&gt;# New - added thanks to student Tue H.!
&lt;/span&gt;

&lt;span class="nd"&gt;@app.function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello_europe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://ipinfo.io/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;country&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello from &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I loved here is the &lt;code&gt;region="eu"&lt;/code&gt; parameter — with one keyword argument you can pin where in the world your function actually executes, which matters for latency, data residency, and sometimes cost.&lt;/p&gt;

&lt;p&gt;Calling it locally vs. remotely is just as simple from a notebook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hello_europe&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;local&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# runs on your machine
&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# runs on Modal's cloud
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running a Real LLM on a GPU
&lt;/h3&gt;

&lt;p&gt;The next step up is running an actual language model. This is where Modal's GPU support and &lt;strong&gt;Secrets&lt;/strong&gt; come in — you don't want to hardcode your Hugging Face token, so you register it once in Modal's dashboard under a name (e.g. &lt;code&gt;huggingface-secret&lt;/code&gt;) and reference it in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# llama.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;

&lt;span class="c1"&gt;# Setup
&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llama&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debian_slim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pip_install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;torch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transformers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accelerate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;secrets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;huggingface-secret&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;GPU&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;T4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;MODEL_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meta-llama/Llama-3.2-3B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="nd"&gt;@app.function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gpu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GPU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1800&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;set_seed&lt;/span&gt;

    &lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MODEL_NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pad_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eos_token&lt;/span&gt;
    &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;padding_side&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;right&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MODEL_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device_map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;set_seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cuda&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_new_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things clicked for me here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;gpu="T4"&lt;/code&gt; is &lt;em&gt;all&lt;/em&gt; it takes to request a GPU-backed container. No CUDA driver wrangling, no Dockerfile.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;timeout=1800&lt;/code&gt; matters because the first call has to download and load model weights — that cold start can take minutes.&lt;/li&gt;
&lt;li&gt;Everything inside the function body that needs the GPU (the &lt;code&gt;transformers&lt;/code&gt; imports, tokenizer, model) is imported &lt;em&gt;inside&lt;/em&gt; the function, so it only happens in the cloud container, not on my laptop.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  From Ephemeral Apps to a Deployed Pricer Service
&lt;/h3&gt;

&lt;p&gt;The really important conceptual jump on Day 1 was going from an &lt;strong&gt;ephemeral app&lt;/strong&gt; (&lt;code&gt;with app.run(): ...&lt;/code&gt;, which spins up and tears down for a single call) to a &lt;strong&gt;deployed app&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run modal deploy &lt;span class="nt"&gt;-m&lt;/span&gt; pricer_service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once deployed, the service runs independently of my notebook, and I can call it from anywhere just by referencing it by name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;
&lt;span class="n"&gt;Pricer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pricer-service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pricer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pricer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pricer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pricer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Quadcast HyperX condenser mic, connects via usb-c to your computer for crystal clear audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is essentially how you'd put a fine-tuned model "behind an API" for a production system — and it's the foundation for the &lt;strong&gt;Specialist Agent&lt;/strong&gt;, which wraps this exact deployed pricer.&lt;/p&gt;

&lt;p&gt;There's also a nice optimization here: by default a Modal container scales down to zero when idle, so the &lt;em&gt;first&lt;/em&gt; call after inactivity can take ~30 seconds to wake up. If you're willing to spend a few extra credits, you can keep a container warm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;
&lt;span class="n"&gt;Pricer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pricer-service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pricer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pricer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pricer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;pricer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_autoscaler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scaledown_window&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# stay warm for 20 minutes
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Modal turns "deploy a fine-tuned model as a microservice" into a one-line decorator and a one-line CLI command. The mental model — &lt;em&gt;write a normal Python function, decorate it, deploy it, call it like a remote object&lt;/em&gt; — is something I'll reuse for any future "specialist model as a service" project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 2: RAG, the Frontier Agent, and an Ensemble of Pricers
&lt;/h2&gt;

&lt;p&gt;Day 2 was about a different way to make a frontier model (GPT-5.1) better at a narrow task — &lt;strong&gt;Retrieval Augmented Generation (RAG)&lt;/strong&gt; — and then about combining &lt;em&gt;multiple&lt;/em&gt; pricing strategies into one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the Vector Store
&lt;/h3&gt;

&lt;p&gt;The first ingredient is a local, open-source &lt;strong&gt;sentence embedding model&lt;/strong&gt;, which turns text into a 384-dimensional vector capturing its meaning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sentence_transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SentenceTransformer&lt;/span&gt;

&lt;span class="n"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SentenceTransformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sentence-transformers/all-MiniLM-L6-v2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Pass in a list of texts, get back a numpy array of vectors
&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A proficient AI engineer who has almost reached the finale of AI Engineering Core Track!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# (384,)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These vectors get stored — along with the product description and metadata (category, price) — in a &lt;strong&gt;Chroma&lt;/strong&gt; vector database, batched 1,000 items at a time across hundreds of thousands of products:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;collection_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;existing_collection_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_collections&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;collection_name&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;existing_collection_names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;tqdm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
        &lt;span class="n"&gt;vectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;metadatas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
        &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;doc_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metadatas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;metadatas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_or_create_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Visualizing the Vector Space
&lt;/h3&gt;

&lt;p&gt;One of the most satisfying moments was reducing those 384-dimensional vectors down to 3D with &lt;strong&gt;t-SNE&lt;/strong&gt; and seeing the products cluster by category — electronics in one corner, musical instruments in another:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.manifold&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TSNE&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;plotly.graph_objects&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt;

&lt;span class="n"&gt;tsne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TSNE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_components&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;reduced_vectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tsne&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Scatter3d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reduced_vectors&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reduced_vectors&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reduced_vectors&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;markers&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;marker&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opacity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Category: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;br&amp;gt;Text: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
    &lt;span class="n"&gt;hoverinfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)])&lt;/span&gt;

&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3D Chroma Vector Store Visualization&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xaxis_title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yaxis_title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zaxis_title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;z&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;margin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's one thing to be told "embeddings capture semantic similarity" — it's another to literally &lt;em&gt;see&lt;/em&gt; the same product categories form tight clusters in 3D space.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Retrieval to Ground a Frontier Model
&lt;/h3&gt;

&lt;p&gt;The actual RAG technique is simple once the vector store exists: for a new product, find its 5 nearest neighbours, and stuff their descriptions &lt;em&gt;and prices&lt;/em&gt; into the prompt as context before asking GPT-5.1 to estimate the price:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_similars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;vec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_embeddings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;n_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][:]&lt;/span&gt;
    &lt;span class="n"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;metadatas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][:]]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;similars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;For context, here are some other items that might be similar to the item you need to estimate.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;similar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;similars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Potentially related product:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;similar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Price is $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;messages_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;similars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Estimate the price of this product. Respond with the price, no explanation&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;make_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;similars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;gpt_5__1_rag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;find_similars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;messages_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;reasoning_effort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This became the heart of the &lt;strong&gt;Frontier Agent&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Ensemble: Combining Three Very Different Models
&lt;/h3&gt;

&lt;p&gt;The biggest "aha" of Day 2 was realizing that three completely different approaches to the &lt;em&gt;same&lt;/em&gt; problem — estimate a product's price — could be &lt;strong&gt;blended&lt;/strong&gt; into something better than any one of them alone:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;RAG + GPT-5.1&lt;/strong&gt; (&lt;code&gt;gpt_5__1_rag&lt;/code&gt;) — frontier model with retrieved context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The fine-tuned Specialist&lt;/strong&gt; running on Modal (&lt;code&gt;specialist&lt;/code&gt;) — small model, fine-tuned specifically on this task&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A classic Deep Neural Network&lt;/strong&gt; trained on the embeddings from Week 6 (&lt;code&gt;deep_neural_network&lt;/code&gt;)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[-+]?\d*\.\d+|\d+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;specialist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pricer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ensemble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;price1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;gpt_5__1_rag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;price2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;specialist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;price3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deep_neural_network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;price1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;price2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;price3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The weighting (&lt;code&gt;0.8 / 0.1 / 0.1&lt;/code&gt;) was chosen because, when evaluated against held-out test data, the RAG-based frontier model was the strongest individual predictor — but the other two still nudged the final estimate in a useful direction. This is essentially a tiny, hand-tuned &lt;strong&gt;mixture-of-experts&lt;/strong&gt;, and it generalizes to most "estimate a number from text" problems: get a few independent estimators, then blend.&lt;/p&gt;

&lt;p&gt;By the end of Day 2, all three of these had been wrapped into proper agent classes — &lt;code&gt;FrontierAgent&lt;/code&gt;, &lt;code&gt;NeuralNetworkAgent&lt;/code&gt;, and &lt;code&gt;EnsembleAgent&lt;/code&gt; — each exposing a simple &lt;code&gt;.price(description)&lt;/code&gt; method, ready to be called by higher-level orchestration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 3: Scanning the Web and Pushing Notifications
&lt;/h2&gt;

&lt;p&gt;Day 2 answered &lt;em&gt;"given a deal, how much is it really worth?"&lt;/em&gt;. Day 3 answered the question that has to come first: &lt;em&gt;"where do the deals come from in the first place, and how do I find out about a good one without staring at a screen?"&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Scanner Agent
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Scanner Agent&lt;/strong&gt; subscribes to deal RSS feeds, scrapes the raw listings, and then asks a cheap LLM (&lt;code&gt;openai/gpt-oss-20b:free&lt;/code&gt; via OpenRouter) to pick the 5 &lt;em&gt;best-described&lt;/em&gt; deals — specifically ones where the price is unambiguous, since deal sites love phrases like "$50 off" which describe the &lt;em&gt;discount&lt;/em&gt;, not the &lt;em&gt;price&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The prompt design here was a small lesson in itself — being explicit about edge cases massively improves reliability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You identify and summarize the 5 most detailed deals from a list, by selecting deals that have the most detailed, high quality description and the most clear price.
Respond strictly in JSON with no explanation, using this format. You should provide the price as a number derived from the description. If the price of a deal isn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t clear, do not include that deal in your response.
Most important is that you respond with the 5 deals that have the most detailed product description with price. It&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s not important to mention the terms of the deal; most important is a thorough description of the product.
Be careful with products that are described as &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$XXX off&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reduced by $XXX&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; - this isn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t the actual price of the product. Only respond with products when you are highly confident about the price. 
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;USER_PROMPT_PREFIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Respond with the most promising 5 deals from this list, selecting those which have the most detailed, high quality product description and a clear price that is greater than 0.
You should rephrase the description to be a summary of the product itself, not the terms of the deal.
Remember to respond with a short paragraph of text in the product_description field for each of the 5 items that you select.
Be careful with products that are described as &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$XXX off&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reduced by $XXX&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; - this isn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t the actual price of the product. Only respond with products when you are highly confident about the price. 

Deals:

&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;USER_PROMPT_SUFFIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;Include exactly 5 deals, no more.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Combined with structured output (Pydantic models via &lt;code&gt;.chat.completions.parse(... response_format=DealSelection ...)&lt;/code&gt;), this guarantees the agent returns &lt;em&gt;exactly&lt;/em&gt; the shape of data the rest of the pipeline expects — no brittle JSON-parsing of free text required.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Messaging Agent and Pushover
&lt;/h3&gt;

&lt;p&gt;The last piece of Day 3 was closing the loop with the outside world: &lt;strong&gt;push notifications&lt;/strong&gt;. &lt;a href="https://pushover.net/" rel="noopener noreferrer"&gt;Pushover&lt;/a&gt; makes this almost embarrassingly easy — register an app, get a user key and an API token, and send a notification with a single HTTP POST:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pushover_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PUSHOVER_USER&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pushover_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PUSHOVER_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pushover_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.pushover.net/1/messages.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Push: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pushover_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pushover_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pushover_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This got wrapped into a &lt;code&gt;MessagingAgent&lt;/code&gt; with a &lt;code&gt;.notify(description, deal_price, estimated_value, url)&lt;/code&gt; method — turning "we found a great deal" into "your phone buzzes."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Agentic systems feel magical, but a lot of the magic is just &lt;em&gt;plumbing&lt;/em&gt; — RSS feeds in, structured LLM output, push notifications out. Getting the plumbing rock-solid (and the prompts very explicit about edge cases) is what makes the "intelligent" part trustworthy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 4: The Autonomous Planning Agent — Teaching an LLM to Use Tools
&lt;/h2&gt;

&lt;p&gt;This was, for me, the most conceptually important day. Up to this point, every agent was called &lt;em&gt;explicitly&lt;/em&gt; by my code: "now run the scanner," "now run the ensemble," "now send a notification." Day 4 flips that around — the LLM itself decides &lt;em&gt;what to do and in what order&lt;/em&gt;, by calling &lt;strong&gt;tools&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Fake Tools, Real Concepts
&lt;/h3&gt;

&lt;p&gt;Before wiring up the real agents, the notebook builds three &lt;em&gt;fake&lt;/em&gt; functions just to understand the tool-calling loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scan_the_internet_for_bargains&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt; This tool scans the internet for great deals and gets a curated list of promising deals &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fake function to scan the internet - this returns a hardcoded set of deals&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;test_results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;estimate_true_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    This tool estimates the true value of a product based on a text description of it
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fake function to estimating true value of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;... - this always returns $300&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; has an estimated true value of $300&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notify_user_of_deal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;deal_price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;estimated_true_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    This tool notifies the user of a great deal, given a description of it, the price of the deal, and the estimated true value
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fake function to notify user of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; which costs &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;deal_price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; and estimate is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;estimated_true_value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notification sent ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each tool also needs a JSON Schema describing its name, description, and parameters — this is what actually gets sent to the LLM so it knows what's available and how to call it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;scan_function&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scan_the_internet_for_bargains&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Returns top bargains scraped from the internet along with the price each item is being offered for&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parameters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;additionalProperties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;notify_function&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notify_user_of_deal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Send the user a push notification about the single most compelling deal; only call this one time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parameters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The description of the item itself scraped from the internet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deal_price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The price offered by this deal scraped from the internet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;estimated_true_value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The estimated actual value that this is worth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The URL of this deal as scraped from the internet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deal_price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;estimated_true_value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;additionalProperties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scan_function&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;estimate_function&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;notify_function&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: The Agent Loop
&lt;/h3&gt;

&lt;p&gt;The real magic is this loop. The LLM is given the tools and a goal; if it decides to call a tool, the code executes the &lt;em&gt;real&lt;/em&gt; Python function and feeds the result back in — and this repeats until the model is satisfied:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_tool_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Actually call the tools associated with this message
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tool_call&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;tool_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
        &lt;span class="n"&gt;raw_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Some models (especially smaller free ones) sometimes return
&lt;/span&gt;            &lt;span class="c1"&gt;# stray/invalid keys (like "") in the arguments JSON, even for
&lt;/span&gt;            &lt;span class="c1"&gt;# functions that take no parameters. Filter to only the keys
&lt;/span&gt;            &lt;span class="c1"&gt;# the function actually accepts.
&lt;/span&gt;            &lt;span class="n"&gt;valid_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;raw_args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;valid_params&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

        &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_call_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;


&lt;span class="n"&gt;system_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You find great deals on bargain products using your tools, and notify the user of the best bargain.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;user_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
First, use your tool to scan the internet for bargain deals. Then for each deal, use your tool to estimate its true value.
Then pick the single most compelling deal where the price is much lower than the estimated true value, and use your tool to notify the user.
Then just reply OK to indicate success.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;system_message&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

&lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;finish_reason&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;handle_tool_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A subtlety that's easy to miss but really matters in practice: smaller, free-tier models sometimes hallucinate extra arguments in their tool calls (like an empty-string key &lt;code&gt;""&lt;/code&gt; for a function that takes no parameters at all). The fix — filtering &lt;code&gt;raw_args&lt;/code&gt; down to only the parameters the function's signature actually accepts via &lt;code&gt;inspect.signature&lt;/code&gt; — is the kind of defensive coding that's invisible until you're debugging a mysterious &lt;code&gt;TypeError&lt;/code&gt; at 11pm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Swap Fakes for Reality
&lt;/h3&gt;

&lt;p&gt;Once the loop works with fake functions, the swap to the &lt;strong&gt;real&lt;/strong&gt; &lt;code&gt;AutonomousPlanningAgent&lt;/code&gt; is almost anticlimactic — same loop, same tool schemas, but &lt;code&gt;scan_the_internet_for_bargains&lt;/code&gt; now really calls the &lt;code&gt;ScannerAgent&lt;/code&gt;, &lt;code&gt;estimate_true_value&lt;/code&gt; really calls the &lt;code&gt;EnsembleAgent&lt;/code&gt;, and &lt;code&gt;notify_user_of_deal&lt;/code&gt; really calls the &lt;code&gt;MessagingAgent&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;products_vectorstore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chromadb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PersistentClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_or_create_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;products&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents.autonomous_planning_agent&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutonomousPlanningAgent&lt;/span&gt;
&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AutonomousPlanningAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Tool/function calling turns an LLM from "a thing that writes text" into "a thing that orchestrates other systems." The hard part isn't the API call — it's (a) writing tight descriptions so the model picks the right tool, and (b) writing tolerant glue code, because the model &lt;em&gt;will&lt;/em&gt; occasionally send malformed arguments.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 5: Bringing It All Together — Framework, Memory, and a Live UI
&lt;/h2&gt;

&lt;p&gt;The final day was about &lt;strong&gt;productionizing&lt;/strong&gt;: wrapping everything in a reusable framework with persistent memory, colored logs, and a Gradio dashboard that updates in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Deal Agent Framework
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;DealAgentFramework&lt;/code&gt; is the top-level orchestrator. It owns the Chroma client, lazily creates the &lt;code&gt;PlanningAgent&lt;/code&gt;, and — critically — persists discovered deals to &lt;code&gt;memory.json&lt;/code&gt; so the system remembers what it's already found across restarts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;chromadb&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents.planning_agent&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PlanningAgent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents.deals&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Opportunity&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.manifold&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TSNE&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;override&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Colors for logging
&lt;/span&gt;&lt;span class="n"&gt;BG_BLUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[44m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;WHITE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[37m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;RESET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[0m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Colors for plot
&lt;/span&gt;&lt;span class="n"&gt;CATEGORIES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Appliances&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Automotive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cell_Phones_and_Accessories&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Electronics&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Musical_Instruments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Office_Products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tools_and_Home_Improvement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Toys_and_Games&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;COLORS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;red&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;brown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;orange&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yellow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;green&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;purple&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cyan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;init_logging&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StreamHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;formatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Formatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[%(asctime)s] [Agents] [%(levelname)s] %(message)s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;datefmt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d %H:%M:%S %z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFormatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formatter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DealAgentFramework&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;DB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;products_vectorstore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;MEMORY_FILENAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;memory.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;init_logging&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chromadb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PersistentClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_memory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_or_create_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;planner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;init_agents_as_needed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;planner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Initializing Agent Framework&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;planner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PlanningAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Agent Framework is ready&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_memory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Opportunity&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MEMORY_FILENAME&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MEMORY_FILENAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;opportunities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Opportunity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opportunities&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write_memory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;opportunity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;opportunity&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MEMORY_FILENAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reset_memory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MEMORY_FILENAME&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MEMORY_FILENAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;truncated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MEMORY_FILENAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;truncated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BG_BLUE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;WHITE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[Agent Framework] &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;RESET&lt;/span&gt;
        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Opportunity&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init_agents_as_needed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Kicking off Planning Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;planner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Planning Agent has completed and returned: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write_memory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;

    &lt;span class="nd"&gt;@classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_plot_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_datapoints&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chromadb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PersistentClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_or_create_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embeddings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metadatas&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_datapoints&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;vectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embeddings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metadatas&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
        &lt;span class="n"&gt;colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;COLORS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CATEGORIES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;tsne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TSNE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_components&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n_jobs&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;reduced_vectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tsne&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reduced_vectors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nc"&gt;DealAgentFramework&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few patterns I want to remember from this file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lazy initialization&lt;/strong&gt; (&lt;code&gt;init_agents_as_needed&lt;/code&gt;) — spinning up the full agent stack (which includes loading models and connecting to vector stores) is expensive, so it only happens once, on first use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory as a flat JSON file&lt;/strong&gt; — no database needed for a project at this scale. &lt;code&gt;memory.json&lt;/code&gt; is literally a list of &lt;code&gt;Opportunity&lt;/code&gt; objects (a deal + an estimated value + a discount), serialized via Pydantic's &lt;code&gt;model_dump()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;reset_memory&lt;/code&gt; as a classmethod&lt;/strong&gt; — a clean way to "rewind" the demo back to a known state (2 saved deals) without touching the running instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Colored terminal logging&lt;/strong&gt; via raw ANSI escape codes (&lt;code&gt;BG_BLUE&lt;/code&gt;, &lt;code&gt;WHITE&lt;/code&gt;, &lt;code&gt;RESET&lt;/code&gt;) — a small touch, but it makes the live log stream from multiple agents &lt;em&gt;much&lt;/em&gt; easier to scan visually.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reformatting ANSI Colors for the Browser
&lt;/h3&gt;

&lt;p&gt;Speaking of colors — the terminal uses ANSI escape codes, but the Gradio UI renders HTML. &lt;code&gt;log_utils.py&lt;/code&gt; is a tiny but clever bridge between the two: it maps each ANSI color combination to a CSS hex color and swaps the escape codes for &lt;code&gt;&amp;lt;span style="color: ..."&amp;gt;&lt;/code&gt; tags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Foreground colors
&lt;/span&gt;&lt;span class="n"&gt;RED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[31m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;GREEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[32m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;YELLOW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[33m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;BLUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[34m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;MAGENTA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[35m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;CYAN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[36m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;WHITE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[37m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;# Background color
&lt;/span&gt;&lt;span class="n"&gt;BG_BLACK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[40m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;BG_BLUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[44m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;# Reset code to return to default color
&lt;/span&gt;&lt;span class="n"&gt;RESET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\033&lt;/span&gt;&lt;span class="s"&gt;[0m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;BG_BLACK&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;RED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#dd0000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;BG_BLACK&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;GREEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#00dd00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;BG_BLACK&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;YELLOW&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#dddd00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;BG_BLACK&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;BLUE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#0000ee&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;BG_BLACK&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;MAGENTA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#aa00dd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;BG_BLACK&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;CYAN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#00dddd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;BG_BLACK&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;WHITE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#87CEEB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;BG_BLUE&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;WHITE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#ff7800&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;span style=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;color: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RESET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every agent in the system logs its activity with a different color (set in its own &lt;code&gt;__init__&lt;/code&gt;), so when this gets rendered in the browser, you can visually tell &lt;em&gt;at a glance&lt;/em&gt; which agent is talking — the planner, the scanner, the frontier agent, etc. — without reading a single word.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Gradio UI: From Static Mockup to Live Dashboard
&lt;/h3&gt;

&lt;p&gt;The UI was built up in layers, which I think is a great way to learn Gradio:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1 — just get something on screen:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Blocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The Price is Right&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fill_width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;div style=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text-align: center;font-size:24px&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;The Price is Right - Deal Hunting Agentic AI&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;div style=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text-align: center;font-size:14px&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;Autonomous agent framework that finds online deals, collaborating with a proprietary fine-tuned LLM deployed on Modal, and a RAG pipeline with a frontier model and Chroma.&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inbrowser&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Layer 2 — add a live data table backed by application state:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Blocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The Price is Right&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fill_width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;initial_deal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Deal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Example description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://cnn.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;initial_opportunity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Opportunity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;initial_deal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;200.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;opportunities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;initial_opportunity&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opps&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;opp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;opp&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;opps&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;opportunities_dataframe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dataframe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Estimate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Discount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;column_widths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;row_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;col_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;max_height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;opportunities&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;opportunities_dataframe&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inbrowser&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A small but important Gradio version note from this layer: in Gradio v5, the &lt;code&gt;height&lt;/code&gt; parameter for &lt;code&gt;Dataframe&lt;/code&gt; was renamed to &lt;code&gt;max_height&lt;/code&gt; — exactly the kind of breaking change that's easy to lose an hour to if you don't know to look for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3 — wire up real agents and make rows clickable:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;agent_framework&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DealAgentFramework&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;agent_framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init_agents_as_needed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Blocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The Price is Right&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fill_width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opportunities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;selected_index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectData&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selected_index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;opportunity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opportunities&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;agent_framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;planner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messenger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opportunity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;opportunities_dataframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;do_select&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;opportunities&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;

&lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inbrowser&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Final Application: Streaming Logs + Background Agent Run + 3D Plot
&lt;/h3&gt;

&lt;p&gt;The fully assembled &lt;code&gt;price_is_right.py&lt;/code&gt; brings everything together: a background thread runs the agent framework's &lt;code&gt;run()&lt;/code&gt; loop, a &lt;code&gt;queue.Queue&lt;/code&gt;-based logging handler streams log lines into the UI in (near) real time, and a 3D Plotly visualization of the product vector store sits alongside the deal table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;gradio&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;deal_agent_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DealAgentFramework&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;log_utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;reformat&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;plotly.graph_objects&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;override&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QueueHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;log_queue&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_queue&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;html_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    &amp;lt;div id=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scrollContent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; style=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;height: 400px; overflow-y: auto; border: 1px solid #ccc; background-color: #222229; padding: 10px;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;
    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
    &amp;lt;/div&amp;gt;
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup_logging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_queue&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;QueueHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;formatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Formatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[%(asctime)s] %(message)s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;datefmt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d %H:%M:%S %z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFormatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formatter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agent_framework&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_agent_framework&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agent_framework&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agent_framework&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DealAgentFramework&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agent_framework&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Blocks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The Price is Right&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fill_width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;log_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;

            &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;table_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opps&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;[&lt;/span&gt;
                        &lt;span class="n"&gt;opp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;opp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;opp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;opp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;opp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;opp&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;opps&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;log_queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result_queue&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;initial_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;table_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_agent_framework&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;final_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
                &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_nowait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;html_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;final_result&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;initial_result&lt;/span&gt;
                    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                            &lt;span class="n"&gt;final_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_nowait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;html_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;final_result&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;initial_result&lt;/span&gt;
                        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;final_result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                                &lt;span class="k"&gt;break&lt;/span&gt;
                            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_plot&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DealAgentFramework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_plot_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_datapoints&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
                        &lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Scatter3d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                            &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                            &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                            &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;markers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;marker&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opacity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;xaxis_title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yaxis_title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zaxis_title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;aspectmode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;manual&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;aspectratio&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="n"&gt;camera&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eye&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                    &lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;margin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;

            &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="n"&gt;new_opportunities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_agent_framework&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;table_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_opportunities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_with_logging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_log_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;log_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;result_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="nf"&gt;setup_logging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                    &lt;span class="n"&gt;result_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;do_run&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

                &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;final_result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;update_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_log_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;log_queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result_queue&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;final_result&lt;/span&gt;

            &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selected_index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectData&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;opportunities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_agent_framework&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;
                &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selected_index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;opportunity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opportunities&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_agent_framework&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;planner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messenger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opportunity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="n"&gt;opportunities_dataframe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dataframe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deals found so far&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Estimate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Discount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column_widths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="n"&gt;row_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;col_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="n"&gt;logs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="n"&gt;plot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;get_plot&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;show_label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_with_logging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opportunities_dataframe&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

            &lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_with_logging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;log_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opportunities_dataframe&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

            &lt;span class="n"&gt;opportunities_dataframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;do_select&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inbrowser&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two patterns I most want to carry forward from this file:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Background work + streaming UI via a generator.&lt;/strong&gt; &lt;code&gt;run_with_logging&lt;/code&gt; is a Python &lt;em&gt;generator&lt;/em&gt; hooked up as a Gradio event handler. It kicks off a worker thread, then repeatedly &lt;code&gt;yield&lt;/code&gt;s updated state — so the UI refreshes live while a slow agentic process runs, instead of freezing for the whole duration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;gr.Timer&lt;/code&gt; for autonomous operation.&lt;/strong&gt; A &lt;code&gt;Timer&lt;/code&gt; set to 300 seconds means the whole "scan → estimate → notify" cycle re-runs automatically every 5 minutes — turning a notebook experiment into something that genuinely behaves like a background agent.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What I'd Tell Past-Me Before Starting This
&lt;/h2&gt;

&lt;p&gt;A few cross-cutting lessons that apply far beyond this specific project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Specialize, then orchestrate.&lt;/strong&gt; Each agent (Scanner, Specialist, Frontier, Ensemble, Messaging, Planner) does one narrow thing well. The "intelligence" of the overall system comes from composition, not from any single giant prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG is cheap leverage.&lt;/strong&gt; Adding 5 similar examples with known prices to a prompt turned out to meaningfully improve a frontier model's estimates — for the cost of a vector lookup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensembling beats picking a favorite.&lt;/strong&gt; Rather than agonizing over which pricing approach is "best," a weighted blend of three approaches (&lt;code&gt;0.8 / 0.1 / 0.1&lt;/code&gt;) outperformed any single one on the held-out test set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool calling needs defensive code.&lt;/strong&gt; The model &lt;em&gt;will&lt;/em&gt; send slightly malformed arguments sometimes, especially smaller/free models. Filter arguments against the real function signature before calling it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory is just a JSON file (for now).&lt;/strong&gt; Don't reach for a database until you actually need one — persisting a &lt;code&gt;List[Opportunity]&lt;/code&gt; to &lt;code&gt;memory.json&lt;/code&gt; was enough to give the system continuity across restarts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generators + threads make agentic UIs feel alive.&lt;/strong&gt; A background worker thread plus a generator-based Gradio handler is a lightweight way to show "the agent is thinking" in real time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small UX details (colored logs, a live 3D plot, clickable rows) make an agentic system feel trustworthy&lt;/strong&gt; — you can &lt;em&gt;see&lt;/em&gt; what it's doing and why, which matters enormously when the system is making autonomous decisions on your behalf.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Putting it all together, &lt;code&gt;DealAgentFramework().run()&lt;/code&gt; now quietly: scans deal feeds, filters to the 5 best-described deals, estimates each one's true value via an ensemble of three models, picks the single best opportunity, saves it to memory, and — if it's a great deal — buzzes my phone. All while a live dashboard shows exactly what's happening and why.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How I Fine-Tuned Llama 3 to Think Like DeepSeek — A Practical Guide to LoRA &amp; QLoRA</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Thu, 11 Jun 2026 06:32:38 +0000</pubDate>
      <link>https://dev.to/m_toqeer/how-i-fine-tuned-llama-3-to-think-like-deepseek-a-practical-guide-to-lora-qlora-5aoi</link>
      <guid>https://dev.to/m_toqeer/how-i-fine-tuned-llama-3-to-think-like-deepseek-a-practical-guide-to-lora-qlora-5aoi</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I turned a base Llama 3.2 model into a step-by-step reasoning machine using a free Colab GPU. Here's exactly how it works.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;So you've heard the buzz around fine-tuning LLMs, but every tutorial either drowns you in math or skips the "why" entirely. This article cuts through both. We'll cover the core concepts — LoRA, QLoRA, quantization — and then walk through a real coding demo that produced a genuinely surprising result: a fine-tuned Llama 3 model that reasons through problems step-by-step, just like DeepSeek.&lt;/p&gt;

&lt;p&gt;Let's get into it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem With Base LLMs
&lt;/h2&gt;

&lt;p&gt;A pre-trained model like Llama or GPT is incredibly general. That's its superpower — and its limitation.&lt;/p&gt;

&lt;p&gt;Your company has private data the model has never seen. Your brand has a specific tone, vocabulary, and format for responses. A base LLM doesn't know any of that.&lt;/p&gt;

&lt;p&gt;You have two main ways to fix this:&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: RAG (Retrieval-Augmented Generation)
&lt;/h3&gt;

&lt;p&gt;RAG doesn't retrain the model at all. Instead, it retrieves relevant chunks from an external knowledge source (a database, PDFs, docs) and injects them into the prompt at inference time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; Cheap, fast to set up, no GPU needed.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; The model still responds in its own generic voice. It can sound robotic, off-brand, or miss the nuanced tone your use case needs.&lt;/p&gt;
&lt;h3&gt;
  
  
  Option 2: Fine-Tuning
&lt;/h3&gt;

&lt;p&gt;Fine-tuning actually retrains the model on your specific dataset — teaching it new knowledge, tone, format, or reasoning style.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; Precise outputs, correct brand voice, specific response formats.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; Computationally expensive, requires a curated dataset, takes time.&lt;/p&gt;

&lt;p&gt;In practice, the industry often &lt;strong&gt;combines both&lt;/strong&gt; — fine-tune for tone and format, use RAG for dynamic knowledge retrieval.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Is Fine-Tuning, Really?
&lt;/h2&gt;

&lt;p&gt;Fine-tuning is a form of &lt;strong&gt;transfer learning&lt;/strong&gt;. You take a model that already understands language, then continue training it on a smaller, task-specific dataset. The model adapts its weights to fit your new data without forgetting everything it already learned.&lt;/p&gt;

&lt;p&gt;The challenge? A 7-billion parameter model has billions of weights to update. Full fine-tuning requires enormous GPU memory — often inaccessible to most developers.&lt;/p&gt;

&lt;p&gt;That's where &lt;strong&gt;LoRA&lt;/strong&gt; comes in.&lt;/p&gt;


&lt;h2&gt;
  
  
  LoRA: Low-Rank Adaptation
&lt;/h2&gt;

&lt;p&gt;LoRA is a &lt;strong&gt;Parameter Efficient Fine-Tuning (PEFT)&lt;/strong&gt; method. The key insight is elegant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Instead of updating all the original model weights, freeze them — and train only a small set of new parameters layered on top.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;During full fine-tuning, you'd update a weight matrix &lt;strong&gt;W&lt;/strong&gt; by computing a change &lt;strong&gt;ΔW&lt;/strong&gt; (delta W). The problem is that ΔW is the same enormous size as W.&lt;/p&gt;

&lt;p&gt;LoRA's trick: &lt;strong&gt;decompose ΔW into two much smaller matrices, A and B&lt;/strong&gt;, where:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ΔW = A × B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If W is a 1024×256 matrix (262,144 parameters), and you set rank &lt;strong&gt;R = 16&lt;/strong&gt;, then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Matrix A is 1024×16&lt;/li&gt;
&lt;li&gt;Matrix B is 16×256&lt;/li&gt;
&lt;li&gt;Total trainable parameters: (1024×16) + (16×256) = &lt;strong&gt;20,480&lt;/strong&gt; instead of 262,144&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's a &lt;strong&gt;~93% reduction&lt;/strong&gt; in parameters to train.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Hyperparameter: Rank (R)
&lt;/h3&gt;

&lt;p&gt;The rank &lt;code&gt;R&lt;/code&gt; controls the trade-off between efficiency and expressiveness.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lower R&lt;/strong&gt; (e.g., 4, 8) → fewer parameters, faster training, less expressive&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Higher R&lt;/strong&gt; (e.g., 16, 32) → more parameters, can capture more complex adaptations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Common starting values are &lt;strong&gt;R = 8 or R = 16&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  QLoRA: When Your GPU Is Too Small
&lt;/h2&gt;

&lt;p&gt;LoRA is efficient, but the base model still needs to fit in memory. A 7B parameter model at full float32 precision requires &lt;strong&gt;~28 GB of GPU RAM&lt;/strong&gt;. Most consumer GPUs and free Colab runtimes offer 12–16 GB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QLoRA&lt;/strong&gt; solves this by adding &lt;strong&gt;quantization&lt;/strong&gt; before applying LoRA.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Is Quantization?
&lt;/h3&gt;

&lt;p&gt;Quantization converts high-precision numbers to lower-precision formats to save memory:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Bytes per value&lt;/th&gt;
&lt;th&gt;7B Model Memory&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;float32&lt;/td&gt;
&lt;td&gt;4 bytes&lt;/td&gt;
&lt;td&gt;~28 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;int8&lt;/td&gt;
&lt;td&gt;1 byte&lt;/td&gt;
&lt;td&gt;~7 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NF4 (4-bit)&lt;/td&gt;
&lt;td&gt;0.5 bytes&lt;/td&gt;
&lt;td&gt;~3.5 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You're essentially compressing the model before training on it. The accuracy loss is surprisingly minimal for most tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  NF4: Normal Float 4
&lt;/h3&gt;

&lt;p&gt;NF4 isn't just regular 4-bit quantization. Neural network weights follow a roughly &lt;strong&gt;normal (bell curve) distribution&lt;/strong&gt;, and NF4 is specifically designed for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of equal-width bins, NF4 uses &lt;strong&gt;percentile-based bins&lt;/strong&gt; that pack more precision where the data is dense (near zero) and less where it's sparse (at the extremes).&lt;/li&gt;
&lt;li&gt;This makes NF4 far more accurate than naive 4-bit quantization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Three Pillars of QLoRA
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;4-bit NF4 Quantization&lt;/strong&gt; — Compress the base model to fit in less memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Double Quantization&lt;/strong&gt; — Quantize the quantization constants themselves (the scale and zero-point values), squeezing out a few more MB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paged Optimizers&lt;/strong&gt; — Uses NVIDIA's unified memory to page optimizer states between GPU and CPU RAM when the GPU runs out of space, preventing out-of-memory crashes during training.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Together, these let you fine-tune a 7B+ model &lt;strong&gt;on a single consumer GPU&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hands-On: Fine-Tuning Llama 3.2 on Google Colab
&lt;/h2&gt;

&lt;p&gt;Let's make this concrete. Here's how the actual demo was built.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Environment:&lt;/strong&gt; Google Colab with a T4 GPU (free tier)&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Library:&lt;/strong&gt; &lt;a href="https://github.com/unslothai/unsloth" rel="noopener noreferrer"&gt;Unsloth&lt;/a&gt; — a highly optimized fine-tuning library&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Model:&lt;/strong&gt; &lt;code&gt;Llama 3.2 3B Instruct&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Dataset:&lt;/strong&gt; &lt;code&gt;ServiceNow R1 Distill SFT&lt;/code&gt; — 172,000 rows of math/logic puzzles with problems, step-by-step reasoning chains, and solutions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;unsloth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Load the Model with 4-bit Quantization
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unsloth&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastLanguageModel&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FastLanguageModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unsloth/Llama-3.2-3B-Instruct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_seq_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;load_in_4bit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# QLoRA quantization
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Configure LoRA
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FastLanguageModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_peft_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                          &lt;span class="c1"&gt;# Rank
&lt;/span&gt;    &lt;span class="n"&gt;target_modules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;o_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gate_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;up_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;down_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;lora_alpha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;lora_dropout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bias&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What are &lt;code&gt;q_proj&lt;/code&gt;, &lt;code&gt;k_proj&lt;/code&gt;, etc.?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
These are the attention projection matrices inside the transformer. LoRA is applied specifically to these layers because they carry the most task-relevant learning signal.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: Format the Dataset
&lt;/h3&gt;

&lt;p&gt;Each training example is structured as a prompt combining the problem, reasoning, and solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;format_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Problem: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;problem&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

&amp;lt;thinking&amp;gt;
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;thought&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
&amp;lt;/thinking&amp;gt;

Solution: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;solution&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;&amp;lt;thinking&amp;gt;&lt;/code&gt; tags teach the model to externalize its reasoning — this is how we get the DeepSeek-like behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Train with SFTTrainer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;trl&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SFTTrainer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TrainingArguments&lt;/span&gt;

&lt;span class="n"&gt;trainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SFTTrainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;train_dataset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;TrainingArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;num_train_epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;per_device_train_batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;learning_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2e-4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;output_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outputs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;trainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;train&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Training time:&lt;/strong&gt; ~20 minutes on a T4 GPU&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Final loss:&lt;/strong&gt; ~0.48 ✅&lt;/p&gt;
&lt;h3&gt;
  
  
  The Result
&lt;/h3&gt;

&lt;p&gt;After fine-tuning, the model was asked:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"How many R's are in the word 'strawberry'?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Before fine-tuning (base model):&lt;/strong&gt; Confidently gives the wrong answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After fine-tuning:&lt;/strong&gt; The model works through it step-by-step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;thinking&amp;gt;
Let me count each letter in "strawberry":
s-t-r-a-w-b-e-r-r-y
Position 3: r
Position 8: r
Position 9: r
That's 3 R's total.
&amp;lt;/thinking&amp;gt;

The word "strawberry" contains 3 R's.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That reasoning pattern — breaking the problem down, checking each step — came entirely from the fine-tuning on the reasoning dataset. The base model didn't do this. The fine-tuned model does.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Should You Use Each Approach?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Best Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Add recent/private knowledge&lt;/td&gt;
&lt;td&gt;RAG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change response tone or format&lt;/td&gt;
&lt;td&gt;Fine-Tuning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Teach step-by-step reasoning&lt;/td&gt;
&lt;td&gt;Fine-Tuning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limited GPU resources&lt;/td&gt;
&lt;td&gt;QLoRA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moderate GPU, need flexibility&lt;/td&gt;
&lt;td&gt;LoRA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production system at scale&lt;/td&gt;
&lt;td&gt;RAG + Fine-Tuning combined&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fine-tuning&lt;/strong&gt; adapts a pre-trained model to your specific task, tone, or data — but it's expensive without the right tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LoRA&lt;/strong&gt; makes it efficient by training only a small set of low-rank adapter matrices, leaving original weights frozen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QLoRA&lt;/strong&gt; takes this further by quantizing the base model to 4-bit (NF4) first, making large model fine-tuning possible on consumer hardware.&lt;/li&gt;
&lt;li&gt;With &lt;strong&gt;Unsloth + Google Colab&lt;/strong&gt;, you can fine-tune a 3B parameter model in under 30 minutes for free.&lt;/li&gt;
&lt;li&gt;The results can be genuinely impressive — a reasoning style the base model didn't have, emergent from the training data alone.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;If you want to go deeper:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Try different ranks (R=4 vs R=32) and observe the loss difference&lt;/li&gt;
&lt;li&gt;Experiment with which target modules to apply LoRA to&lt;/li&gt;
&lt;li&gt;Combine your fine-tuned model with a RAG pipeline for maximum power&lt;/li&gt;
&lt;li&gt;Push your model to Hugging Face Hub and share it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fine-tuning used to require a research lab. Now it takes a free GPU and 30 minutes. There's never been a better time to build something genuinely your own.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Found this useful? Drop a reaction or share it with someone building with LLMs. Questions or corrections? I'm all ears in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>deepseek</category>
      <category>llm</category>
      <category>machinelearning</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a Meeting Minutes AI From Raw Audio</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Tue, 02 Jun 2026 04:23:16 +0000</pubDate>
      <link>https://dev.to/m_toqeer/build-a-meeting-minutes-ai-from-raw-audio-42en</link>
      <guid>https://dev.to/m_toqeer/build-a-meeting-minutes-ai-from-raw-audio-42en</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A complete walkthrough of speech transcription, LLM inference, tokenization, and 4-bit quantization. Built with Whisper, Llama 3.2, and the HuggingFace ecosystem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Skill level:&lt;/strong&gt; Intermediate &amp;nbsp;|&amp;nbsp; &lt;strong&gt;Runtime:&lt;/strong&gt; Google Colab T4 GPU &amp;nbsp;|&amp;nbsp; &lt;strong&gt;Models:&lt;/strong&gt; Whisper-medium, Llama-3.2-3B&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Two-Step Pipeline&lt;/li&gt;
&lt;li&gt;Tokenization&lt;/li&gt;
&lt;li&gt;Quantization&lt;/li&gt;
&lt;li&gt;The Chat Template&lt;/li&gt;
&lt;li&gt;Neural Networks and Transformers&lt;/li&gt;
&lt;li&gt;Tradeoffs&lt;/li&gt;
&lt;li&gt;What You Can Build Next&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Two-Step Pipeline
&lt;/h2&gt;

&lt;p&gt;You feed an audio file into a Python script. Minutes later, you get formatted meeting minutes, a summary, and action items. No manual transcription, no human editor.&lt;/p&gt;

&lt;p&gt;The notebook splits the problem into two clean stages. Stage one converts audio to text. Stage two converts text to structured meeting minutes.&lt;/p&gt;



&lt;p&gt;

&lt;/p&gt;



&lt;p&gt;Both stages run locally on a free Colab T4 GPU. Stage one uses Whisper from OpenAI (or the API version). Stage two uses Meta's Llama 3.2 3B, loaded with 4-bit quantization so it fits in GPU memory.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is ASR?&lt;/strong&gt; Automatic Speech Recognition converts raw audio waveforms into text. Whisper treats audio as a sequence prediction problem: it predicts the next token given all previous audio frames.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Two Transcription Options
&lt;/h3&gt;

&lt;p&gt;The notebook gives you two paths. The open-source path runs Whisper locally on the GPU. The API path sends the audio to OpenAI's servers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;

&lt;span class="c1"&gt;# Open-source: runs locally on T4 GPU
&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;automatic-speech-recognition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai/whisper-medium.en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cuda&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;return_timestamps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;transcription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# API option: offloads to OpenAI servers
&lt;/span&gt;&lt;span class="n"&gt;AUDIO_MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o-mini-transcribe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;transcription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transcriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AUDIO_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Open-source path&lt;/th&gt;
&lt;th&gt;API path&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Per minute of audio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data privacy&lt;/td&gt;
&lt;td&gt;Stays local&lt;/td&gt;
&lt;td&gt;Leaves your environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup&lt;/td&gt;
&lt;td&gt;Needs GPU&lt;/td&gt;
&lt;td&gt;Works anywhere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Offline use&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Tokenization: How Text Becomes Numbers
&lt;/h2&gt;

&lt;p&gt;Language models do not read text. They read numbers. Tokenization is the bridge between the two.&lt;/p&gt;

&lt;p&gt;A tokenizer splits your text into subword chunks called tokens, then maps each chunk to an integer ID. The word "quantization" might split into tokens like &lt;code&gt;["quant", "ization"]&lt;/code&gt;, producing IDs like &lt;code&gt;[42891, 2065]&lt;/code&gt;. The model works with these integer sequences from start to finish.&lt;/p&gt;



&lt;p&gt;

&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLAMA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pad_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eos_token&lt;/span&gt;

&lt;span class="c1"&gt;# apply_chat_template formats your messages list
# into the exact token sequence Llama expects
&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply_chat_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cuda&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;pad_token&lt;/code&gt; matters:&lt;/strong&gt; When you process multiple sequences in a batch, they need equal length. Shorter sequences get padded with a special token. Setting &lt;code&gt;pad_token = eos_token&lt;/code&gt; tells the tokenizer which ID to use. Without it, the tokenizer raises an error during batched inference.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The tokenizer also inserts special tokens like &lt;code&gt;&amp;lt;|begin_of_text|&amp;gt;&lt;/code&gt; and role markers for &lt;code&gt;system&lt;/code&gt; and &lt;code&gt;user&lt;/code&gt;. These are instructions to the model, not content. &lt;code&gt;apply_chat_template&lt;/code&gt; handles all of this based on the model's expected format.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quantization: Shrinking the Model to Fit
&lt;/h2&gt;

&lt;p&gt;A 3B parameter model in full 32-bit precision needs around 12 GB of GPU memory. A free T4 has 15 GB total. 4-bit quantization compresses each weight from 32 bits down to 4 bits, cutting memory use by roughly 8x.&lt;/p&gt;



&lt;p&gt;

&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;quant_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BitsAndBytesConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;load_in_4bit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bnb_4bit_use_double_quant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# quantize the quantization constants too
&lt;/span&gt;    &lt;span class="n"&gt;bnb_4bit_compute_dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bfloat16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# compute in bfloat16 for speed
&lt;/span&gt;    &lt;span class="n"&gt;bnb_4bit_quant_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nf4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;           &lt;span class="c1"&gt;# NormalFloat4: better for normal distributions
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;LLAMA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device_map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantization_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;quant_config&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What NF4 means:&lt;/strong&gt; NormalFloat4 is a 4-bit data type designed for neural network weights, which typically follow a normal distribution. It places more quantization levels near zero (where most weights cluster) and fewer at the extremes. This beats a naive 4-bit integer scheme in accuracy on nearly every benchmark.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Double quantization&lt;/strong&gt; (&lt;code&gt;bnb_4bit_use_double_quant=True&lt;/code&gt;) quantizes the quantization constants themselves too. It saves about 0.4 bits per parameter on top of base 4-bit compression. Small gain, no cost.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;device_map="auto"&lt;/code&gt; tells HuggingFace which layers go on GPU versus CPU. For a 3B model on a T4, everything fits on GPU.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Chat Template: Speaking the Model's Language
&lt;/h2&gt;

&lt;p&gt;Instruction-tuned models like Llama 3.2 Instruct were fine-tuned on conversations in a specific format. Send text in the wrong format and the model either ignores your instructions or produces garbage. The chat template enforces the right format every time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;system_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You produce minutes of meetings from transcripts, with summary,
key discussion points, takeaways and action items with owners,
in markdown format without code blocks.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;user_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Below is an extract transcript of a Denver council meeting.
Please write minutes in markdown without code blocks, including:
- a summary with attendees, location and date
- discussion points
- takeaways
- action items with owners

Transcription:
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transcription&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;system_message&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# apply_chat_template wraps messages in Llama's expected token format
&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply_chat_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;System vs user roles:&lt;/strong&gt; The system message sets the model's persona and output constraints. The user message contains the actual task. Keeping them separate gives you fine-grained control: swap the transcript without touching output format instructions, or change the output format without touching the transcript.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After &lt;code&gt;apply_chat_template&lt;/code&gt;, your clean Python dictionaries become a single integer tensor. That tensor goes directly into &lt;code&gt;generate()&lt;/code&gt;. No string manipulation after this point — everything is numbers on the GPU.&lt;/p&gt;




&lt;h2&gt;
  
  
  Neural Networks and Transformer Quantization
&lt;/h2&gt;

&lt;p&gt;A transformer model is a stack of layers. Each layer contains weight matrices stored as 2D arrays of floating point numbers. During a forward pass, the model multiplies your input token embeddings by these matrices over and over, applying attention at each step.&lt;/p&gt;



&lt;p&gt;

&lt;/p&gt;



&lt;p&gt;The weight matrices in feed-forward layers are what quantization compresses. At inference time, BitsAndBytes dequantizes each weight block just before the matrix multiplication, performs the multiplication in &lt;code&gt;bfloat16&lt;/code&gt;, then moves on. The full 4-bit weights stay compressed in GPU memory at all times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;streamer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TextStreamer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_new_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;streamer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;streamer&lt;/span&gt;  &lt;span class="c1"&gt;# streams tokens to stdout as generated
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;TextStreamer&lt;/code&gt; prints tokens to the console as the model generates them. The model produces one token per forward pass. You see output build word by word because each word triggers a separate forward pass through all layers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tradeoffs to Know Before You Ship
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Whisper medium vs large
&lt;/h3&gt;

&lt;p&gt;The notebook uses &lt;code&gt;whisper-medium.en&lt;/code&gt;. The &lt;code&gt;.en&lt;/code&gt; suffix means English-only. It runs faster and uses less memory than the multilingual version. If your meetings include non-English speakers, swap to &lt;code&gt;whisper-large-v3&lt;/code&gt; and expect roughly 3x more GPU memory usage.&lt;/p&gt;

&lt;h3&gt;
  
  
  3B vs larger Llama models
&lt;/h3&gt;

&lt;p&gt;Llama 3.2 3B handles summarization well. For long meetings with complex technical jargon, a 70B model produces more accurate action items. You cannot run 70B on a free T4, even with 4-bit quantization. You need either a paid Colab Pro instance or API inference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Float16 vs bfloat16
&lt;/h3&gt;

&lt;p&gt;Whisper runs in &lt;code&gt;torch.float16&lt;/code&gt;. Llama's quantized compute runs in &lt;code&gt;bfloat16&lt;/code&gt;. Both are 16-bit formats. Float16 has higher precision for small values. Bfloat16 has a wider dynamic range and is less prone to overflow on modern hardware.&lt;/p&gt;



&lt;p&gt;

&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Colab CUDA error that trips everyone up:&lt;/strong&gt; If you see &lt;code&gt;CUDA is required but not available for bitsandbytes&lt;/code&gt;, your runtime was recycled by Google. Fix: Kernel menu, Disconnect and delete runtime. Reconnect to a fresh T4. Rerun from the top. Do not touch package versions.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What You Can Build Next
&lt;/h2&gt;

&lt;p&gt;The notebook is a foundation. A few extensions that follow naturally:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speaker diarization.&lt;/strong&gt; Add &lt;code&gt;pyannote-audio&lt;/code&gt; before the Whisper step to tag each segment with a speaker ID. Feed those labels into the prompt so Llama assigns action items to the right person.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gradio streaming interface.&lt;/strong&gt; Student Emad S. adapted the notebook to stream tokens into a Gradio UI using &lt;code&gt;TextIteratorStreamer&lt;/code&gt; and Python background threads. The result is a browser-based app where you upload audio and watch minutes appear in real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Persistent storage.&lt;/strong&gt; Write the output to a Google Doc via the Drive API. Every meeting auto-archives with a timestamp and a searchable transcript.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MeetingBank dataset&lt;/td&gt;
&lt;td&gt;&lt;a href="https://huggingface.co/datasets/huuuyeah/meetingbank" rel="noopener noreferrer"&gt;huuuyeah/meetingbank on HuggingFace&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audio dataset&lt;/td&gt;
&lt;td&gt;&lt;a href="https://huggingface.co/datasets/huuuyeah/MeetingBank_Audio/tree/main" rel="noopener noreferrer"&gt;MeetingBank Audio&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Denver extract MP3&lt;/td&gt;
&lt;td&gt;&lt;a href="https://drive.google.com/file/d/1N_kpSojRR5RYzupz6nqM8hMSoEF_R7pU/view?usp=sharing" rel="noopener noreferrer"&gt;Google Drive&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Whisper model&lt;/td&gt;
&lt;td&gt;&lt;code&gt;openai/whisper-medium.en&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama model&lt;/td&gt;
&lt;td&gt;&lt;code&gt;meta-llama/Llama-3.2-3B-Instruct&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gradio variation&lt;/td&gt;
&lt;td&gt;&lt;a href="https://colab.research.google.com/drive/1Ja5zyniyJo5y8s1LKeCTSkB2xyDPOt6D" rel="noopener noreferrer"&gt;Emad S. Colab&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;em&gt;Source dataset: MeetingBank. Models: openai/whisper-medium.en and meta-llama/Llama-3.2-3B-Instruct. Quantization: bitsandbytes. Runtime: Google Colab T4 GPU. Framework: HuggingFace Transformers 4.57.6.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>machinelearning</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>API Authentication: What It Is, Why It Matters, and Which Method to Use</title>
      <dc:creator>M TOQEER ZIA</dc:creator>
      <pubDate>Fri, 22 May 2026 05:57:57 +0000</pubDate>
      <link>https://dev.to/m_toqeer/api-authentication-what-it-is-why-it-matters-and-which-method-to-use-72o</link>
      <guid>https://dev.to/m_toqeer/api-authentication-what-it-is-why-it-matters-and-which-method-to-use-72o</guid>
      <description>&lt;p&gt;Every API you build is a door. Without authentication, that door has no lock.&lt;/p&gt;

&lt;p&gt;Anyone with the URL can walk in, read your data, abuse your resources, or impersonate your users. This article breaks down how API authentication works, the four most common methods, and the one distinction that trips up most developers: authentication versus authorization.&lt;/p&gt;




&lt;h2&gt;
  
  
  What API Authentication Actually Does
&lt;/h2&gt;

&lt;p&gt;API authentication verifies the identity of whoever is making a request.&lt;/p&gt;

&lt;p&gt;Before your API returns any data, it asks one question: who are you? The client must prove its identity. If it cannot, the request fails.&lt;/p&gt;

&lt;p&gt;Without this, your API is open to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data leaks from anonymous requests&lt;/li&gt;
&lt;li&gt;Resource abuse from bots making unlimited calls&lt;/li&gt;
&lt;li&gt;Unauthorized access to user data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Authentication also gives you control beyond just blocking strangers. Once you know who is calling your API, you can apply rate limits per client, audit exactly who accessed what and when, and assign different permission levels to different clients.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Four Main API Authentication Methods
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. HTTP Basic Authentication
&lt;/h3&gt;

&lt;p&gt;The client sends a username and password with every request. The credentials are Base64-encoded and placed in the HTTP header.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F1%2F1c%2FHTTP_Basic_Auth_Diagram.svg%2F800px-HTTP_Basic_Auth_Diagram.svg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F1%2F1c%2FHTTP_Basic_Auth_Diagram.svg%2F800px-HTTP_Basic_Auth_Diagram.svg.png" alt="HTTP Basic Auth Flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Base64 is encoding, not encryption. Anyone who intercepts the request reads the credentials in plain text.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Dead simple to implement&lt;/li&gt;
&lt;li&gt;Supported natively by every HTTP client&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Credentials travel with every single request&lt;/li&gt;
&lt;li&gt;No hashing or encryption by default&lt;/li&gt;
&lt;li&gt;Completely insecure without HTTPS&lt;/li&gt;
&lt;li&gt;No way to revoke a single session without changing the password&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use it when:&lt;/strong&gt; You need the fastest possible prototype on an internal tool behind HTTPS, and you will replace it later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real incident:&lt;/strong&gt; In 2022, a misconfigured CI/CD pipeline exposed Basic Auth credentials in plain text logs. The credentials granted access to a private package registry. Thousands of packages were at risk before the team caught it. The fix required rotating every credential across every service.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. API Key Authentication
&lt;/h3&gt;

&lt;p&gt;The API provider issues a unique key to each client. The client sends this key with every request, either in the query string, request header, or a cookie.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/data&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api.example.com&lt;/span&gt;
&lt;span class="na"&gt;X-API-Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sk_live_4f8a92bc...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;API keys are easy to generate and easy to rotate. They give you per-client tracking out of the box.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Simple to implement and issue&lt;/li&gt;
&lt;li&gt;Easy to monitor per-client usage&lt;/li&gt;
&lt;li&gt;Easy to revoke a compromised key without touching other clients&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Functions like a password: whoever holds the key has full access&lt;/li&gt;
&lt;li&gt;No expiry by default&lt;/li&gt;
&lt;li&gt;Developers frequently hard-code keys in source code, which ends up in public repositories&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real incident:&lt;/strong&gt; In 2023, a developer pushed an OpenAI API key to a public GitHub repository. Automated bots scraped it within seconds. The key accumulated thousands of dollars in charges before the developer noticed. GitHub now scans for exposed secrets, but the damage happens before the scan completes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use it when:&lt;/strong&gt; You are building a server-to-server integration where you control both ends and your key never touches a browser or mobile client.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. JWT (JSON Web Token) Authentication
&lt;/h3&gt;

&lt;p&gt;When a user logs in, the server generates a JWT and returns it to the client. Every subsequent request includes this token. The server validates the token on each request without looking up a session database.&lt;/p&gt;

&lt;p&gt;A JWT has three parts, separated by dots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;header.payload.signature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The payload contains the user's identity and claims:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user_8821"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jane@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1716560000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The signature is cryptographically generated. If anyone tampers with the payload, the signature breaks and the server rejects the token.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Stateless: the server stores no session data&lt;/li&gt;
&lt;li&gt;Scales horizontally with no shared session store&lt;/li&gt;
&lt;li&gt;Token carries its own expiry&lt;/li&gt;
&lt;li&gt;Works across domains and services&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Tokens cannot be invalidated before expiry without extra infrastructure (a blocklist)&lt;/li&gt;
&lt;li&gt;If a token is stolen before it expires, the attacker has full access until expiry&lt;/li&gt;
&lt;li&gt;Developers sometimes skip signature verification, which defeats the purpose entirely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real incident:&lt;/strong&gt; In 2022, researchers found that several APIs accepted JWTs with the algorithm set to "none," meaning no signature was required. Any attacker could forge a token claiming to be any user. The flaw existed because developers copied example code without reading the security notes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use it when:&lt;/strong&gt; You need stateless authentication across multiple services, especially in a microservices architecture where a shared session store creates a bottleneck.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. OAuth 2.0
&lt;/h3&gt;

&lt;p&gt;OAuth 2.0 is the standard used when your API needs to act on behalf of a user without ever seeing their password.&lt;/p&gt;

&lt;p&gt;When you click "Sign in with Google" on any app, you are using OAuth 2.0. Google authenticates you, then issues an &lt;strong&gt;access token&lt;/strong&gt; to the app. The app uses that token to call Google's APIs on your behalf. Your Google password never touches the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User → App → Google (login) → Access Token → App uses token → Google API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access tokens expire. They can be revoked. If an app is compromised, you revoke its token without changing your Google password.&lt;/p&gt;

&lt;p&gt;OAuth 2.0 also introduced refresh tokens, which let apps get new access tokens silently without asking the user to log in again.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Users never share credentials with third-party apps&lt;/li&gt;
&lt;li&gt;Tokens expire and are revocable&lt;/li&gt;
&lt;li&gt;Granular scopes: an app gets only the permissions it needs&lt;/li&gt;
&lt;li&gt;The gold standard for public APIs&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;More complex to implement than Basic Auth or API keys&lt;/li&gt;
&lt;li&gt;Misconfigured redirect URIs are a common attack vector&lt;/li&gt;
&lt;li&gt;Token storage on mobile and SPA clients requires care&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real incident:&lt;/strong&gt; In 2021, a flaw in Facebook's OAuth implementation let attackers use malformed redirect URIs to steal access tokens. Hundreds of millions of accounts were potentially affected. The root cause: insufficient validation of where tokens were sent after authorization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use it when:&lt;/strong&gt; You are building a public API, integrating with third-party services, or giving users the ability to connect their accounts to other apps.&lt;/p&gt;




&lt;h2&gt;
  
  
  Comparison: Which Method for Which Situation
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Security&lt;/th&gt;
&lt;th&gt;Complexity&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Basic Auth&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Very Low&lt;/td&gt;
&lt;td&gt;Internal tools, quick prototypes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Keys&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Server-to-server, developer APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JWT&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Stateless services, microservices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OAuth 2.0&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Public APIs, third-party integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Authentication vs. Authorization: The Distinction That Matters
&lt;/h2&gt;

&lt;p&gt;These two words get used interchangeably. They are not the same.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt; answers: who are you?&lt;/p&gt;

&lt;p&gt;Your API verifies the client's identity. A valid JWT, a matching API key, a Google OAuth token. If verification passes, the client is authenticated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authorization&lt;/strong&gt; answers: what are you allowed to do?&lt;/p&gt;

&lt;p&gt;A regular user on your platform is authenticated. That does not mean they are authorized to delete other users' accounts. Authorization determines what an authenticated identity is permitted to access or modify.&lt;/p&gt;

&lt;p&gt;A concrete example:&lt;/p&gt;

&lt;p&gt;You log into a hospital system with your nurse credentials. Authentication passed. You are inside. But when you try to access the prescriptions database, the system checks your role. Nurses read records. Only physicians write prescriptions. Authorization denied.&lt;/p&gt;

&lt;p&gt;In code terms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request arrives → Authentication middleware (who are you?) → Passes
Request continues → Authorization middleware (can you do this?) → Passes or fails
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most security breaches that happen after login are &lt;strong&gt;authorization&lt;/strong&gt; failures, not authentication failures. The attacker is legitimately logged in, then exploits missing or weak permission checks to access data they should not see.&lt;/p&gt;

&lt;p&gt;The 2021 Peloton API breach is a clear example. The API was authenticated: requests required valid user tokens. But the authorization layer was broken. Any authenticated user could query any other user's private profile data by changing a user ID in the request. Millions of records were exposed to any logged-in user.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pros and Cons of API Authentication Overall
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;Prevents unauthorized access to sensitive data&lt;/li&gt;
&lt;li&gt;Gives you per-client rate limiting and usage tracking&lt;/li&gt;
&lt;li&gt;Creates a complete audit trail: who accessed what and when&lt;/li&gt;
&lt;li&gt;Lets you revoke access instantly when credentials are compromised&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Adds latency to every request (token validation, key lookup)&lt;/li&gt;
&lt;li&gt;Poor key management by clients creates vulnerabilities you cannot fully control&lt;/li&gt;
&lt;li&gt;More complex auth flows increase surface area for implementation mistakes&lt;/li&gt;
&lt;li&gt;Stateful session approaches do not scale without a shared data store&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What to Take Away
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Basic Auth&lt;/strong&gt; is the simplest option and the least secure. Use HTTPS. Replace it early.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Keys&lt;/strong&gt; are practical for developer-facing APIs. Treat them like passwords. Never put them in client-side code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JWT&lt;/strong&gt; gives you stateless, scalable authentication. Always validate the signature. Set short expiry times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OAuth 2.0&lt;/strong&gt; is the right choice for any API that acts on behalf of users or integrates with third parties.&lt;/li&gt;
&lt;li&gt;Authentication tells you who the caller is. Authorization tells you what they can do. You need both.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The method you choose shapes how your API scales, how you handle breaches, and how much trust your clients place in your system. Get the foundation right before building on top of it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have questions about OAuth flows, JWT security, or RBAC authorization patterns? Drop them in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>beginners</category>
      <category>security</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
