<?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: uday kiran chellu</title>
    <description>The latest articles on DEV Community by uday kiran chellu (@uday163_cuk).</description>
    <link>https://dev.to/uday163_cuk</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%2F4147105%2Fb84d0be3-4466-41f7-9154-c69064ed3059.png</url>
      <title>DEV Community: uday kiran chellu</title>
      <link>https://dev.to/uday163_cuk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/uday163_cuk"/>
    <language>en</language>
    <item>
      <title>Why I Built a Strict A/B Test Into Our Sales Agent Before Writing Any Logic</title>
      <dc:creator>uday kiran chellu</dc:creator>
      <pubDate>Mon, 28 Sep 2026 16:16:38 +0000</pubDate>
      <link>https://dev.to/uday163_cuk/why-i-built-a-strict-ab-test-into-our-sales-agent-before-writing-any-logic-3h4m</link>
      <guid>https://dev.to/uday163_cuk/why-i-built-a-strict-ab-test-into-our-sales-agent-before-writing-any-logic-3h4m</guid>
      <description>&lt;h1&gt;
  
  
  Why I Built a Strict A/B Test Into Our Sales Agent Before Writing Any Logic
&lt;/h1&gt;

&lt;p&gt;When engineers start building AI agents, they usually make a massive, unspoken assumption: &lt;em&gt;more context is always better&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;When I was building DealMind AI—a sales assistant designed to prepare reps for their next call—I almost fell into this trap. I knew that feeding the latest CRM notes into a large language model (LLM) wasn't enough. The agent needed historical memory to understand the full narrative of a deal. I decided to integrate &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt; to retrieve relevant past interactions.&lt;/p&gt;

&lt;p&gt;But how could I mathematically prove that this retrieved memory was actually helping the agent, rather than just confusing it with older, irrelevant noise?&lt;/p&gt;

&lt;p&gt;Instead of just blindly wiring up the retrieval pipeline and hoping for the best, I built a strict A/B comparison routing architecture directly into our FastAPI backend. Here is the story of how I forced our AI to prove its worth, and why you should do the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Untested Memory
&lt;/h2&gt;

&lt;p&gt;If you dump a user's prompt, the current CRM state, and five retrieved historical memories into an LLM, it will confidently generate a response. But you have no baseline. If the agent recommends a "phased rollout", did it do so because the historical memory revealed a budget constraint, or did it just hallucinate a generic B2B sales tactic?&lt;/p&gt;

&lt;p&gt;Without a baseline, you cannot tune your retrieval strategy. If your retrieval is too broad, you dilute the LLM's attention. I needed a way to isolate the exact impact of &lt;a href="https://vectorize.io/what-is-agent-memory" rel="noopener noreferrer"&gt;agent memory&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture: Dual-Routing the Agent
&lt;/h2&gt;

&lt;p&gt;To solve this, I designed a &lt;code&gt;/comparison&lt;/code&gt; endpoint. When the frontend requests call preparation, it doesn't just hit a single logic flow. It triggers a dual-execution path.&lt;/p&gt;

&lt;p&gt;The key to a fair A/B test is isolating variables. Both paths must use the exact same user query and the exact same underlying LLM. The only variable we toggle is the contextual payload.&lt;/p&gt;

&lt;p&gt;Here is what the routing logic looks like in our &lt;code&gt;prepare.py&lt;/code&gt; file:&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F99ujjvrqhv9zr6h0n6em.jpeg" 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%2F99ujjvrqhv9zr6h0n6em.jpeg" alt=" " width="800" height="338"&gt;&lt;/a&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="nd"&gt;@router.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/comparison&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;compare_preparation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PrepareRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Fetch ONLY the most recent CRM note for the baseline
&lt;/span&gt;    &lt;span class="n"&gt;latest_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_latest_crm_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deal_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;without_memories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;latest_context&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;latest_context&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;response&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;status&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;success&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_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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deal_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;without_memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;with_hindsight&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# PATH A: The Baseline (Without Memory)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;both&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;without_memory&lt;/span&gt;&lt;span class="sh"&gt;"&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="c1"&gt;# Analyze using only the latest snapshot
&lt;/span&gt;            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;without_memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;analyze_deal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;memories&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;without_memories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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;error&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;Without Memory Analysis Error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&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="c1"&gt;# PATH B: The Enriched Route (With Hindsight)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;both&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;with_hindsight&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="c1"&gt;# ... [Hindsight retrieval logic executes here] ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By supporting a &lt;code&gt;mode="both"&lt;/code&gt; flag, I could hit the endpoint via cURL during development and immediately see a side-by-side JSON comparison of how the agent's logic shifted when historical memory was injected.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results: Catching the Invisible Objections
&lt;/h2&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F128t7v5gjhc8yhiyi4iq.jpeg" 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%2F128t7v5gjhc8yhiyi4iq.jpeg" alt=" " width="800" height="143"&gt;&lt;/a&gt;&lt;br&gt;
The A/B test immediately paid off. By comparing the two outputs side-by-side, the value of historical retrieval became undeniably clear.&lt;/p&gt;

&lt;p&gt;In the "Without Memory" baseline, the agent saw a prospect scrutinizing pricing in the latest CRM note. Predictably, it recommended generic defensive tactics, like offering a 10% discount. &lt;/p&gt;

&lt;p&gt;But in the "With Hindsight" flow, the agent received the chronological history retrieved by Hindsight. It saw that three weeks prior, the prospect had explicitly stated budget was &lt;em&gt;not&lt;/em&gt; a blocker. The agent's recommendation entirely flipped. Instead of offering a discount, it correctly diagnosed a structural shift in the prospect's stance and recommended proposing a phased rollout to mitigate the newfound risk.&lt;/p&gt;

&lt;p&gt;I didn't have to guess if the memory integration worked; the A/B test proved it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Building this A/B testing architecture taught me a few critical lessons about engineering LLM applications:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Establish a naive baseline early
&lt;/h3&gt;

&lt;p&gt;Never build a complex RAG (Retrieval-Augmented Generation) pipeline before building a naive baseline. If your baseline (just the latest CRM note) gets you 80% of the way there, you might not need a complex memory layer. If it fails terribly, you now have a yardstick to measure your improvements against.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Fair comparisons require isolated variables
&lt;/h3&gt;

&lt;p&gt;When testing your agent's memory, you cannot change the underlying model temperature, the system prompt, or the user query. The &lt;em&gt;only&lt;/em&gt; thing that should change between your control and your experiment is the retrieved contextual payload.&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%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa2uvmy8s4vuvc58l4d24.jpeg" 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%2Fa2uvmy8s4vuvc58l4d24.jpeg" alt=" " width="800" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Expose the A/B test to the user
&lt;/h3&gt;

&lt;p&gt;We ended up keeping the A/B test in the final UI. Users can literally click a toggle to see what the agent would have recommended without historical memory. This contrast builds massive user trust, as they can visually see the exact value the memory layer provides.&lt;/p&gt;

&lt;p&gt;If you are building an AI agent, stop assuming your context layer is working. Build a strict A/B test, isolate your baseline, and check out the &lt;a href="https://hindsight.vectorize.io/" rel="noopener noreferrer"&gt;Hindsight docs&lt;/a&gt; to see how surgical memory retrieval can completely change your agent's reasoning.&lt;/p&gt;

&lt;p&gt;Shout-out to: &lt;a href="https://code.in/" rel="noopener noreferrer"&gt;Code.in&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
      <category>api</category>
    </item>
  </channel>
</rss>
