<?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: Vemula Srinath</title>
    <description>The latest articles on DEV Community by Vemula Srinath (@vemula_srinath_094827dac6).</description>
    <link>https://dev.to/vemula_srinath_094827dac6</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%2F4150257%2Feea8621e-deb3-40d7-bf8c-01d89887ddf3.jpg</url>
      <title>DEV Community: Vemula Srinath</title>
      <link>https://dev.to/vemula_srinath_094827dac6</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vemula_srinath_094827dac6"/>
    <language>en</language>
    <item>
      <title>I Gave an AI Support Agent Two Memories with Hindsight</title>
      <dc:creator>Vemula Srinath</dc:creator>
      <pubDate>Tue, 29 Sep 2026 16:26:59 +0000</pubDate>
      <link>https://dev.to/vemula_srinath_094827dac6/i-gave-an-ai-support-agent-two-memories-with-hindsight-3kd1</link>
      <guid>https://dev.to/vemula_srinath_094827dac6/i-gave-an-ai-support-agent-two-memories-with-hindsight-3kd1</guid>
      <description>&lt;p&gt;The first time an AI support agent tells a customer to restart an application, that can be reasonable. The tenth time it gives the same advice to the same customer, it starts to feel broken.&lt;/p&gt;

&lt;p&gt;That was the problem I wanted to solve with Continuum, a support agent for the fictional SaaS product Nimbus Sync. The interesting part wasn't making another chatbot that could answer support questions. It was deciding what the agent should remember—and at what level.&lt;/p&gt;

&lt;p&gt;I ended up giving it two kinds of memory with Hindsight: one for the individual customer, and another for problems that appear across customers.&lt;/p&gt;

&lt;p&gt;That distinction changed the way I thought about support 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/continuum_two_level_memory.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/continuum_two_level_memory.png" alt="Continuum two-level memory architecture" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One conversation can contain two kinds of knowledge
&lt;/h2&gt;

&lt;p&gt;A support conversation can tell us something about a customer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what environment they use&lt;/li&gt;
&lt;li&gt;what they have already tried&lt;/li&gt;
&lt;li&gt;what happened in previous tickets&lt;/li&gt;
&lt;li&gt;how they prefer to communicate&lt;/li&gt;
&lt;li&gt;whether a previous workaround actually solved the problem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the same conversation can also tell us something about the product.&lt;/p&gt;

&lt;p&gt;If several customers report similar symptoms, the useful information is no longer only about one customer. It may be evidence of a recurring or systemic issue.&lt;/p&gt;

&lt;p&gt;Those are different memories.&lt;/p&gt;

&lt;p&gt;Customer memory answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What do I know about this customer?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Shared memory answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What do I know about this problem across customers?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Continuum keeps those concerns separate using Hindsight.&lt;/p&gt;

&lt;p&gt;For the customer-specific side, the agent maintains a private memory bank containing the customer's relevant history and environment.&lt;/p&gt;

&lt;p&gt;For the shared side, it maintains a common bank containing knowledge about recurring issues and patterns across the customer base.&lt;/p&gt;

&lt;p&gt;The separation matters because I don't want a customer's private context to become everybody's context. At the same time, I don't want every new customer to start from zero when the support system has already seen the same failure repeatedly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The support loop
&lt;/h2&gt;

&lt;p&gt;Memory isn't bolted onto the side of the agent. It is part of the response loop.&lt;/p&gt;

&lt;p&gt;The actual &lt;code&gt;WithMemoryStrategy&lt;/code&gt; makes that explicit:&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;respond&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;customer_id&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;ticket_id&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;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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;AgentReply&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;retain_customer_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ticket_id&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;known&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="nf"&gt;recall_known_issues&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;outcome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ReflectOutcome&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="nf"&gt;reflect_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;customer_id&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;known&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;retain_resolution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outcome&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;outcome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_known_issue&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;retain_known_issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a useful sequence here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new message
    ↓
retain customer context
    ↓
recall known issues
    ↓
reflect with memory + directives
    ↓
return response + structured signals
    ↓
retain the outcome
    ↓
if it is a known issue, update shared memory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last step is the part I care about most. The agent isn't just reading memory. It writes the outcome of the interaction back into memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why one memory layer wasn't enough
&lt;/h2&gt;

&lt;p&gt;Imagine a customer says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"My files aren't syncing again. I already restarted the application."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A stateless support agent has very little to work with. It might respond with the same troubleshooting step:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Try restarting the application."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But customer-specific memory can tell the agent that this person has already tried that.&lt;/p&gt;

&lt;p&gt;Now consider a different customer reporting:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"My sync queue has been stuck since yesterday."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Suppose the support system has seen similar reports from several other customers. Shared memory can contain the emerging pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product: Nimbus Sync
Module: sync engine
Symptom: sync queue stops processing
Observed across: multiple customers
Known resolution/workaround: retained from previous tickets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second customer does not need to know anything about the first customer. The useful knowledge is about the problem itself.&lt;/p&gt;

&lt;p&gt;This is the difference between remembering a customer and remembering a problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Hindsight is actually doing
&lt;/h2&gt;

&lt;p&gt;I put Hindsight behind a &lt;code&gt;MemoryService&lt;/code&gt; adapter so the rest of the application doesn't need to talk directly to the Hindsight SDK.&lt;/p&gt;

&lt;p&gt;The important operation is &lt;code&gt;reflect()&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;response&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reflect&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;customer_bank_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_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;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;budget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;context&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&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;context_lines&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;response_schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AGENT_REFLECT_SCHEMA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;apply_all_directives&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="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The call is doing more than generating prose.&lt;/p&gt;

&lt;p&gt;The response schema asks for structured information alongside the customer-facing reply. In the current implementation, that schema includes &lt;code&gt;sentiment&lt;/code&gt;, &lt;code&gt;resolved&lt;/code&gt;, &lt;code&gt;root_cause_tag&lt;/code&gt;, &lt;code&gt;is_known_issue&lt;/code&gt;, and &lt;code&gt;module&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;AGENT_REFLECT_SCHEMA&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;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;reply&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;sentiment&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;enum&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;positive&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;neutral&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;frustrated&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;angry&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;resolved&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;boolean&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;root_cause_tag&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="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;null&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;is_known_issue&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;boolean&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;module&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="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;null&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;reply&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;sentiment&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;resolved&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;is_known_issue&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;The response goes back to the customer.&lt;/p&gt;

&lt;p&gt;The structured fields go back into the application and memory system.&lt;/p&gt;

&lt;p&gt;That makes the LLM call part of a memory pipeline rather than treating it as a simple text-generation endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small naming detail that matters
&lt;/h2&gt;

&lt;p&gt;The design brief for this work describes the systemic signal as &lt;code&gt;is_systemic&lt;/code&gt;. In the current repository, I implemented the same boundary as &lt;code&gt;is_known_issue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I prefer being explicit about that distinction because the code is the source of truth.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_known_issue&lt;/code&gt; is defined as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;true if this matches a systemic issue affecting multiple customers, not a one-off.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the conceptual flow is still:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;one customer's ticket
        ↓
does this match a broader recurring problem?
        ↓
       yes
        ↓
shared / known-issue memory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the actual field name in the implementation is &lt;code&gt;is_known_issue&lt;/code&gt;, not &lt;code&gt;is_systemic&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping private and shared knowledge separate
&lt;/h2&gt;

&lt;p&gt;The two banks have different missions.&lt;/p&gt;

&lt;p&gt;The customer bank is instructed to remember things such as the customer's environment, previous troubleshooting attempts, resolutions, and sentiment.&lt;/p&gt;

&lt;p&gt;The shared bank has a different boundary: it should retain the technical shape of recurring issues and their resolutions, without storing an individual customer's personal details.&lt;/p&gt;

&lt;p&gt;That distinction is encoded directly in the Hindsight configuration:&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;SHARED_BANK_MISSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are the collective memory of every support ticket ever resolved for &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{product}, across all customers. Remember which bugs and issues are &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recurring, which modules they affect, and what fix or workaround &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resolved them. Do not store any individual customer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s personal details &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;here — only the technical shape of the issue and its resolution.&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;p&gt;I like this because the privacy boundary isn't merely an assumption in application code. It is part of the memory bank's mission.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete before and after
&lt;/h2&gt;

&lt;p&gt;Without memory, two similar tickets can look almost identical to the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ticket 1:
"My files aren't syncing."

Ticket 2:
"My files aren't syncing."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model has to rediscover the context each time.&lt;/p&gt;

&lt;p&gt;With the two memory levels, the second interaction can have additional information available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customer memory:
- This customer has already tried restarting.
- They previously reinstalled the application.

Shared memory:
- Other customers have reported similar sync failures.
- A recurring issue has already been associated with the sync module.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the agent has two different reasons to change its response.&lt;/p&gt;

&lt;p&gt;Customer memory prevents it from repeating the customer's own failed troubleshooting steps.&lt;/p&gt;

&lt;p&gt;Shared memory helps it recognize that the issue may not be isolated.&lt;/p&gt;

&lt;p&gt;That is a much more useful form of continuity than simply replaying the last few chat messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  The closed learning loop
&lt;/h2&gt;

&lt;p&gt;The repository makes the distinction between memory and no memory structural.&lt;/p&gt;

&lt;p&gt;There are two strategies:&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;class&lt;/span&gt; &lt;span class="nc"&gt;NoMemoryStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AgentStrategy&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;off&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;respond&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;customer_id&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;ticket_id&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;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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;AgentReply&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&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;return&lt;/span&gt; &lt;span class="nc"&gt;AgentReply&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;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;memory_mode&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;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;meta&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;note&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;stateless — no memory used&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;The memory-backed strategy follows the retain → recall → reflect → retain loop.&lt;/p&gt;

&lt;p&gt;That gives me a useful comparison: the exact same support input can be handled with memory on or with a stateless baseline.&lt;/p&gt;

&lt;p&gt;I don't have to claim that memory is better because it sounds better. The application can show what context was used, how many memories and directives were involved, and which known issues matched.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard part: deciding what deserves to be remembered
&lt;/h2&gt;

&lt;p&gt;The most interesting engineering problem here isn't storing information. Storage is easy.&lt;/p&gt;

&lt;p&gt;The harder question is deciding what information is worth retaining.&lt;/p&gt;

&lt;p&gt;If every sentence becomes a permanent memory, the memory layer becomes noisy.&lt;/p&gt;

&lt;p&gt;If nothing is retained, the agent remains stateless.&lt;/p&gt;

&lt;p&gt;The useful middle ground is to retain distilled information: outcomes, recurring issues, customer context, and other facts that can change how a future support interaction should be handled.&lt;/p&gt;

&lt;p&gt;That is also why the shared bank shouldn't simply be a copy of every customer conversation.&lt;/p&gt;

&lt;p&gt;It should contain knowledge that has crossed the boundary from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This happened to one customer."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We've seen this problem across customers."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The known-issue signal is part of that boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  One limitation I would not hide
&lt;/h2&gt;

&lt;p&gt;Identifying a systemic issue is not the same thing as proving one.&lt;/p&gt;

&lt;p&gt;A single unusual ticket can resemble an existing problem. Conversely, several customers can describe the same symptom while having different root causes.&lt;/p&gt;

&lt;p&gt;That means &lt;code&gt;is_known_issue&lt;/code&gt; should be treated as a structured signal used by the system, not as an infallible diagnosis.&lt;/p&gt;

&lt;p&gt;The memory layer can accumulate evidence, but the quality of that memory still depends on the quality of the agent's interpretation and the policies around retention.&lt;/p&gt;

&lt;p&gt;That is one reason I like keeping memory operations behind a dedicated service boundary. It gives me a clear place to improve retrieval, retention, and validation rules without spreading memory logic throughout the application.&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%2Fvsakp7esq124537vf8f8.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%2Fvsakp7esq124537vf8f8.png" alt="Continuum support agent architecture showing customer and shared memory with Hindsight" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;h3&gt;
  
  
  1. Memory needs scope
&lt;/h3&gt;

&lt;p&gt;"Remember everything" isn't a useful memory strategy.&lt;/p&gt;

&lt;p&gt;Some information belongs to one customer. Some belongs to the organization. Making that distinction explicit makes the system easier to reason about.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Retrieval and retention are equally important
&lt;/h3&gt;

&lt;p&gt;Remembering something later is only useful if the right thing was retained in the first place.&lt;/p&gt;

&lt;p&gt;The memory loop therefore has two sides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;retain → recall → use → retain again
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ignoring either side weakens the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Structured output makes memory actionable
&lt;/h3&gt;

&lt;p&gt;A response string is difficult for application code to reason about.&lt;/p&gt;

&lt;p&gt;Signals such as &lt;code&gt;resolved&lt;/code&gt;, &lt;code&gt;root_cause_tag&lt;/code&gt;, and &lt;code&gt;is_known_issue&lt;/code&gt; create explicit hooks between model output and application behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Shared memory changes the unit of learning
&lt;/h3&gt;

&lt;p&gt;Customer memory is about continuity for one person.&lt;/p&gt;

&lt;p&gt;Shared memory lets the support system accumulate knowledge about recurring product behavior.&lt;/p&gt;

&lt;p&gt;That changes the unit of memory from "this conversation" to "this problem pattern."&lt;/p&gt;

&lt;h3&gt;
  
  
  5. More memory isn't automatically better
&lt;/h3&gt;

&lt;p&gt;The goal isn't to give an agent the largest possible history.&lt;/p&gt;

&lt;p&gt;The goal is to give it the right context for the current decision.&lt;/p&gt;

&lt;p&gt;That's the part I'm most interested in continuing to explore with Continuum: not how much an agent can remember, but how deliberately it can decide what belongs in memory—and who should benefit from that memory.&lt;/p&gt;

&lt;p&gt;If you're interested in the memory layer itself, start with the &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight GitHub repository&lt;/a&gt;, the &lt;a href="https://hindsight.vectorize.io/" rel="noopener noreferrer"&gt;Hindsight documentation&lt;/a&gt;, and Vectorize's explanation of &lt;a href="https://vectorize.io/what-is-agent-memory" rel="noopener noreferrer"&gt;agent memory&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>agents</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
