<?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: Manyala Vivek Vardhan</title>
    <description>The latest articles on DEV Community by Manyala Vivek Vardhan (@vivekdebugtech).</description>
    <link>https://dev.to/vivekdebugtech</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%2F4146701%2Fccbe52e3-aa52-4d76-bff7-a5cce126ea29.png</url>
      <title>DEV Community: Manyala Vivek Vardhan</title>
      <link>https://dev.to/vivekdebugtech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vivekdebugtech"/>
    <language>en</language>
    <item>
      <title>How I Used Hindsight to Catch Sales Objections Buried in CRM Logs</title>
      <dc:creator>Manyala Vivek Vardhan</dc:creator>
      <pubDate>Mon, 28 Sep 2026 09:13:45 +0000</pubDate>
      <link>https://dev.to/vivekdebugtech/how-i-used-hindsight-to-catch-sales-objections-buried-in-crm-logs-11l4</link>
      <guid>https://dev.to/vivekdebugtech/how-i-used-hindsight-to-catch-sales-objections-buried-in-crm-logs-11l4</guid>
      <description>&lt;p&gt;If you've ever worked in B2B sales—or written software for people who do—you know that the biggest threat to closing a deal isn't a competitor. It's forgetting what your prospect told you three months ago. &lt;/p&gt;

&lt;p&gt;When I set out to build DealMind AI, the goal was simple: build an agent that analyzes a prospect's history and generates a highly specific preparation brief for the sales representative's next call. I initially thought I could just take the latest notes from the CRM, dump them into a large language model (LLM), and ask it for a strategic recommendation.&lt;/p&gt;

&lt;p&gt;It didn't work. By only looking at the latest CRM snapshot, the agent completely missed the chronological narrative. If a prospect suddenly claimed they didn't have budget, the agent would just recommend offering a discount. What the agent &lt;em&gt;didn't&lt;/em&gt; know was that three weeks prior, the prospect had explicitly stated budget was not a blocker. &lt;/p&gt;

&lt;p&gt;To catch these structural shifts and contradictions, the agent needed long-term memory. Here is the story of how I built an architecture that retrieves relevant historical context at the exact moment it's needed using &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt;, and the hard lessons I learned about LLM nondeterminism along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture: Splitting the Timeline
&lt;/h2&gt;

&lt;p&gt;The core problem with standard CRM workflows is that they prioritize the present. To give our agent a true sense of time, I split the context gathering into two distinct flows: the immediate CRM reality, and the deep historical memory.&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%2Ffe93kxht4nusgru4q8ym.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%2Ffe93kxht4nusgru4q8ym.png" alt=" " width="800" height="611"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(Above: Our architecture splits standard CRM retrieval from historical Hindsight retrieval)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Our backend is built on FastAPI. When a request comes in for call preparation, we do not blindly append the entire deal history into the prompt. That approach quickly bloats the context window, increases latency, and degrades the LLM's reasoning capabilities. Instead, we use &lt;a href="https://vectorize.io/what-is-agent-memory" rel="noopener noreferrer"&gt;agent memory&lt;/a&gt; to actively recall only the interactions that matter right now.&lt;/p&gt;

&lt;p&gt;Here is the high-level flow of how we retrieve that memory:&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;# Contextualize the user's query with the specific deal ID
&lt;/span&gt;&lt;span class="n"&gt;scoped_query&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;[Deal: &lt;/span&gt;&lt;span class="si"&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="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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Recall relevant historical memories from our Hindsight bank
&lt;/span&gt;&lt;span class="n"&gt;hindsight_resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hindsight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;bank_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hindsight_bank_id&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;scoped_query&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Safely extract the historical text
&lt;/span&gt;&lt;span class="n"&gt;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;ans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hindsight_resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then take these chronological &lt;code&gt;memories&lt;/code&gt; and stitch them together with the latest CRM snapshot. This enriched, multi-turn payload is sent to our Groq-powered analysis service. &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%2Fp2sqi2e1huoi27rjy9nx.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%2Fp2sqi2e1huoi27rjy9nx.png" alt=" " width="799" height="157"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(Above: The agent detects the exact contradiction regarding budget by comparing the retrieved timeline)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Because we prompt the LLM to specifically look for changes in position rather than just summarizing the text, the agent immediately flags contradictions. It alerts the representative: &lt;em&gt;"Earlier, they said budget was open. Now, they are asking for a phased rollout due to budget constraints."&lt;/em&gt; This transforms raw historical text into an actionable strategic warning.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pitfall of LLM Nondeterminism
&lt;/h2&gt;

&lt;p&gt;Getting the agent to recall the active deal's history was only half the battle. I also wanted the agent to draw upon institutional knowledge by looking at &lt;em&gt;past&lt;/em&gt; closed deals that faced similar objections. &lt;/p&gt;

&lt;p&gt;I implemented a secondary cross-deal retrieval query. I asked Hindsight to look across all our historical data for closed deals involving budget objections and pricing pressure. Hindsight successfully returned the historical context, including the identifiers of past deals (e.g., &lt;code&gt;DEAL-002&lt;/code&gt; which we won, and &lt;code&gt;DEAL-003&lt;/code&gt; which we lost).&lt;/p&gt;

&lt;p&gt;Initially, I passed these cross-deal memories directly into the LLM and asked it to format a &lt;code&gt;similar_deals&lt;/code&gt; JSON array containing the outcome and tactics used.&lt;/p&gt;

&lt;p&gt;This was a massive mistake.&lt;/p&gt;

&lt;p&gt;LLMs are inherently nondeterministic. Because &lt;code&gt;DEAL-003&lt;/code&gt; was a &lt;em&gt;lost&lt;/em&gt; deal, the LLM frequently decided it was "irrelevant" to successful call preparation and silently dropped it from the output array. Sometimes the UI would show both deals; sometimes it would only show the win. &lt;/p&gt;

&lt;p&gt;I was relying on the LLM to map retrieved data into a strict data structure, and it was silently filtering my evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix: Deterministic Grounding
&lt;/h2&gt;

&lt;p&gt;I realized I needed to stop trusting the LLM to handle the existence of seeded historical records. The LLM is great at generating natural-language evidence summaries, but it should not be in charge of data integrity.&lt;/p&gt;

&lt;p&gt;I completely refactored the backend route. Instead of asking the LLM to format the deals, I used Python to intercept the raw text returned by Hindsight, regex-extract the deal IDs, and map them deterministically against our actual database (in this case, a seeded &lt;code&gt;closed_deals.json&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%2Fon4oasnmb20nqyf8sma7.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%2Fon4oasnmb20nqyf8sma7.png" alt=" " width="547" height="212"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(Above: Decoupling the ID extraction from the LLM ensures deterministic grounding)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By decoupling the retrieval mapping from the LLM generation, the system became 100% deterministic. The LLM still writes the strategic analysis, but the historical evidence—the actual WON and LOST deals rendered in the UI—is explicitly grounded in verified data.&lt;/p&gt;

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

&lt;p&gt;Building DealMind AI taught me several harsh but valuable lessons about designing memory-augmented agents:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Separate your context layers
&lt;/h3&gt;

&lt;p&gt;Do not blindly merge your agent's immediate reality (the latest CRM note) with its long-term memory. By keeping them conceptually separate, you can run A/B baseline comparisons to prove that your retrieval pipeline is actually adding value, rather than just adding noise.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Guard against current-deal contamination
&lt;/h3&gt;

&lt;p&gt;When retrieving "similar past examples," your agent will almost always retrieve the active deal's own history because it is an exact semantic match. You must actively filter out the active context ID (&lt;code&gt;if match != request.deal_id&lt;/code&gt;) before presenting the results to the user.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Let the LLM reason, let the code map
&lt;/h3&gt;

&lt;p&gt;The LLM should be used to detect contradictions and generate strategy. It should &lt;em&gt;not&lt;/em&gt; be used to decide whether a historical record exists. Use tools like Hindsight to retrieve the raw unstructured memory, but use strict deterministic code to map those retrieved identifiers back to your source of truth.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Visibility builds trust
&lt;/h3&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%2Fma5ruuauedpu9ttlv8lg.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%2Fma5ruuauedpu9ttlv8lg.png" alt=" " width="798" height="244"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(Above: Exposing the WON/LOST past deal evidence directly in the UI builds immediate trust)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If an agent gives a sales rep a contrarian piece of advice based on a three-month-old memory, the rep will ignore it unless the provenance is obvious. We exposed the exact number of memories used and rendered the WON/LOST past deal evidence directly in the UI. If the user can't see the memory, they won't trust the insight.&lt;/p&gt;

&lt;p&gt;If you are building agents that need to remember complex, multi-turn interactions without bloating context windows, you should check out the &lt;a href="https://hindsight.vectorize.io/" rel="noopener noreferrer"&gt;Hindsight docs&lt;/a&gt;. It completely changed how I think about providing chronological context to language models.&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>python</category>
      <category>react</category>
      <category>software</category>
    </item>
  </channel>
</rss>
