<?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: Harshith Kotla</title>
    <description>The latest articles on DEV Community by Harshith Kotla (@harshithkotla).</description>
    <link>https://dev.to/harshithkotla</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%2F4150597%2Faf741d15-c3c0-437e-b989-1e05a4929a37.jpg</url>
      <title>DEV Community: Harshith Kotla</title>
      <link>https://dev.to/harshithkotla</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harshithkotla"/>
    <language>en</language>
    <item>
      <title>Support Agents Should Remember What Worked</title>
      <dc:creator>Harshith Kotla</dc:creator>
      <pubDate>Tue, 29 Sep 2026 17:49:56 +0000</pubDate>
      <link>https://dev.to/harshithkotla/support-agents-should-remember-what-worked-1ipf</link>
      <guid>https://dev.to/harshithkotla/support-agents-should-remember-what-worked-1ipf</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%2Feimyujetdwkm1zhuojeb.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%2Feimyujetdwkm1zhuojeb.png" alt="This is how our agent's interface looks" width="800" height="384"&gt;&lt;/a&gt;&lt;br&gt;
The first version of our support agent could answer a customer's question.&lt;/p&gt;

&lt;p&gt;That wasn't enough.&lt;/p&gt;

&lt;p&gt;A customer could report a payment failure, follow a troubleshooting step, get the problem resolved, and come back later with the exact same issue. The agent would see a new message and essentially start over.&lt;/p&gt;

&lt;p&gt;The interesting part wasn't making the agent generate another good answer.&lt;/p&gt;

&lt;p&gt;It was making the next answer different because of what happened previously.&lt;/p&gt;

&lt;p&gt;That became the core idea behind our Support Memory Agent: instead of treating previous conversations as simple chat history, we wanted to retain support experiences — including the problem, the action taken, and the outcome — and recall those experiences when they become relevant again.&lt;/p&gt;

&lt;p&gt;From Conversation History to Support Experience&lt;/p&gt;

&lt;p&gt;A typical support interaction looks something like this:&lt;/p&gt;

&lt;p&gt;Customer&lt;br&gt;
   ↓&lt;br&gt;
Problem&lt;br&gt;
   ↓&lt;br&gt;
Troubleshooting&lt;br&gt;
   ↓&lt;br&gt;
Solution&lt;br&gt;
   ↓&lt;br&gt;
Conversation ends&lt;/p&gt;

&lt;p&gt;The problem is what happens when the customer returns.&lt;/p&gt;

&lt;p&gt;The previous conversation might exist somewhere, but simply having access to old messages doesn't mean the agent will use the most useful information from them.&lt;/p&gt;

&lt;p&gt;For support, the important information isn't every sentence the customer previously typed.&lt;/p&gt;

&lt;p&gt;It's things like:&lt;/p&gt;

&lt;p&gt;Customer: Rahul&lt;br&gt;
Platform: Android&lt;/p&gt;

&lt;p&gt;Issue:&lt;br&gt;
Payment failure&lt;/p&gt;

&lt;p&gt;Action:&lt;br&gt;
Clear app cache&lt;/p&gt;

&lt;p&gt;Outcome:&lt;br&gt;
Failed&lt;/p&gt;

&lt;p&gt;Action:&lt;br&gt;
Update PayFlow app&lt;/p&gt;

&lt;p&gt;Outcome:&lt;br&gt;
Resolved&lt;/p&gt;

&lt;p&gt;That is much closer to an experience than a transcript.&lt;/p&gt;

&lt;p&gt;We built our system around this distinction.&lt;/p&gt;

&lt;p&gt;Where Hindsight Fits&lt;/p&gt;

&lt;p&gt;We use Hindsight GitHub as the persistent memory layer.&lt;/p&gt;

&lt;p&gt;The application has two important memory operations.&lt;/p&gt;

&lt;p&gt;The first is recall.&lt;/p&gt;

&lt;p&gt;When Rahul sends a new support request, the backend retrieves relevant previous experiences before asking the language model to generate a response.&lt;/p&gt;

&lt;p&gt;The second is retain.&lt;/p&gt;

&lt;p&gt;When a support interaction reaches an outcome, we store the experience so it can be used later.&lt;/p&gt;

&lt;p&gt;The resulting loop looks like this:&lt;/p&gt;

&lt;p&gt;Customer message&lt;br&gt;
       ↓&lt;br&gt;
Backend&lt;br&gt;
       ↓&lt;br&gt;
Hindsight recall&lt;br&gt;
       ↓&lt;br&gt;
Relevant previous experiences&lt;br&gt;
       ↓&lt;br&gt;
LLM&lt;br&gt;
       ↓&lt;br&gt;
Personalized response&lt;br&gt;
       ↓&lt;br&gt;
Support outcome&lt;br&gt;
       ↓&lt;br&gt;
Hindsight retain&lt;/p&gt;

&lt;p&gt;The important detail is that Hindsight isn't simply sitting beside the application as a passive database.&lt;/p&gt;

&lt;p&gt;The recalled memories become part of the context used to determine the next response.&lt;/p&gt;

&lt;p&gt;You can learn more about the memory system in the Hindsight documentation and Vectorize's agent memory overview.&lt;/p&gt;

&lt;p&gt;The Interaction That Changed the Design&lt;/p&gt;

&lt;p&gt;Our simplest test case was a payment failure.&lt;/p&gt;

&lt;p&gt;Imagine Rahul contacts support for the first time:&lt;/p&gt;

&lt;p&gt;“My payment failed.”&lt;/p&gt;

&lt;p&gt;At this point, there isn't a useful previous experience to recall.&lt;/p&gt;

&lt;p&gt;The agent can ask for the platform and begin troubleshooting.&lt;/p&gt;

&lt;p&gt;Rahul says he's using Android.&lt;/p&gt;

&lt;p&gt;Suppose the first troubleshooting attempt is clearing the app cache.&lt;/p&gt;

&lt;p&gt;It doesn't work.&lt;/p&gt;

&lt;p&gt;We then try updating the PayFlow app and retrying the payment.&lt;/p&gt;

&lt;p&gt;This time, the payment succeeds.&lt;/p&gt;

&lt;p&gt;Instead of throwing away that information when the conversation ends, we retain the outcome.&lt;/p&gt;

&lt;p&gt;The memory now contains something like:&lt;/p&gt;

&lt;p&gt;Rahul experienced a payment failure&lt;br&gt;
on Android.&lt;/p&gt;

&lt;p&gt;Clearing the cache failed.&lt;/p&gt;

&lt;p&gt;Updating the PayFlow app resolved&lt;br&gt;
the payment failure.&lt;/p&gt;

&lt;p&gt;Now comes the interesting part.&lt;/p&gt;

&lt;p&gt;A few days later Rahul returns:&lt;/p&gt;

&lt;p&gt;“My payment failed again.”&lt;/p&gt;

&lt;p&gt;Without useful memory, the agent can only reason from the current message.&lt;/p&gt;

&lt;p&gt;With memory, the backend recalls Rahul's previous support experience.&lt;/p&gt;

&lt;p&gt;The response can now become:&lt;/p&gt;

&lt;p&gt;“Updating the PayFlow app resolved this issue for you before, while clearing the cache didn't. Let's check your app version first.”&lt;/p&gt;

&lt;p&gt;That difference is the entire point of the project.&lt;/p&gt;

&lt;p&gt;The agent isn't simply producing a more detailed answer.&lt;/p&gt;

&lt;p&gt;The previous outcome changed what it recommends next.&lt;/p&gt;

&lt;p&gt;The API Is Deliberately Simple&lt;/p&gt;

&lt;p&gt;We kept the application architecture relatively small.&lt;/p&gt;

&lt;p&gt;The frontend communicates with a Node.js and Express backend.&lt;/p&gt;

&lt;p&gt;For a support message, the frontend sends:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{&lt;br&gt;
  "customerId": "rahul-001",&lt;br&gt;
  "customerName": "Rahul",&lt;br&gt;
  "platform": "Android",&lt;br&gt;
  "message": "My payment failed again."&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The backend handles the request through:&lt;/p&gt;

&lt;p&gt;POST /api/chat&lt;/p&gt;

&lt;p&gt;The backend then recalls relevant memories, passes those memories to the language model, and returns the response together with the memories that were used.&lt;/p&gt;

&lt;p&gt;A simplified response looks like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{&lt;br&gt;
  "success": true,&lt;br&gt;
  "reply": "Updating the PayFlow app resolved this issue for you before...",&lt;br&gt;
  "memoryUsed": true,&lt;br&gt;
  "memories": [&lt;br&gt;
    {&lt;br&gt;
      "text": "Rahul resolved his payment failure by updating the PayFlow app.",&lt;br&gt;
      "type": "observation"&lt;br&gt;
    }&lt;br&gt;
  ],&lt;br&gt;
  "memoryCount": 1&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We intentionally return the recalled memories to the frontend.&lt;/p&gt;

&lt;p&gt;That makes the system easier to inspect and, more importantly, makes the memory behavior visible to the person using the application.&lt;/p&gt;

&lt;p&gt;The Support Agent&lt;/p&gt;

&lt;p&gt;The support request flows through a small service layer rather than putting everything inside the API route.&lt;/p&gt;

&lt;p&gt;A simplified version of the flow looks like this:&lt;/p&gt;

&lt;p&gt;`async function handleSupportMessage({&lt;br&gt;
  customerId,&lt;br&gt;
  customerName,&lt;br&gt;
  platform,&lt;br&gt;
  message&lt;br&gt;
}) {&lt;br&gt;
  const memories = await recallSupportMemory({&lt;br&gt;
    customerId,&lt;br&gt;
    query: message,&lt;br&gt;
    platform&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;const reply = await generateSupportResponse({&lt;br&gt;
    customerName,&lt;br&gt;
    platform,&lt;br&gt;
    message,&lt;br&gt;
    memories&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;return {&lt;br&gt;
    reply,&lt;br&gt;
    memoryUsed: memories.length &amp;gt; 0,&lt;br&gt;
    memories&lt;br&gt;
  };&lt;br&gt;
}`&lt;/p&gt;

&lt;p&gt;This separation matters.&lt;/p&gt;

&lt;p&gt;The route is responsible for handling HTTP requests.&lt;/p&gt;

&lt;p&gt;The support-agent service coordinates the workflow.&lt;/p&gt;

&lt;p&gt;The Hindsight service handles memory.&lt;/p&gt;

&lt;p&gt;The LLM service handles response generation.&lt;/p&gt;

&lt;p&gt;That gives us a structure like:&lt;/p&gt;

&lt;p&gt;server/&lt;br&gt;
└── src/&lt;br&gt;
    ├── app.js&lt;br&gt;
    ├── routes/&lt;br&gt;
    │   ├── chat.js&lt;br&gt;
    │   └── outcome.js&lt;br&gt;
    ├── services/&lt;br&gt;
    │   ├── hindsight.js&lt;br&gt;
    │   ├── llm.js&lt;br&gt;
    │   └── supportAgent.js&lt;br&gt;
    └── config/&lt;br&gt;
        ├── clients.js&lt;br&gt;
        └── env.js&lt;/p&gt;

&lt;p&gt;The goal was to keep the memory layer independent from the rest of the support logic.&lt;/p&gt;

&lt;p&gt;Outcome Capture Is Just as Important as Recall&lt;/p&gt;

&lt;p&gt;One design decision became obvious while building this.&lt;/p&gt;

&lt;p&gt;If we only recalled memories but never recorded outcomes, the system wouldn't have a meaningful feedback loop.&lt;/p&gt;

&lt;p&gt;That's why we added:&lt;/p&gt;

&lt;p&gt;POST /api/outcome&lt;/p&gt;

&lt;p&gt;The request records information such as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{&lt;br&gt;
  "customerId": "rahul-001",&lt;br&gt;
  "customerName": "Rahul",&lt;br&gt;
  "platform": "Android",&lt;br&gt;
  "issue": "Payment failure",&lt;br&gt;
  "action": "Update PayFlow app and retry",&lt;br&gt;
  "outcome": "resolved",&lt;br&gt;
  "notes": "Payment succeeded after the app update."&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The backend turns this into a support experience and retains it in Hindsight.&lt;/p&gt;

&lt;p&gt;We can do the same for failed troubleshooting.&lt;/p&gt;

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

&lt;p&gt;Clear app cache → failed&lt;br&gt;
Update app → resolved&lt;/p&gt;

&lt;p&gt;Both are useful.&lt;/p&gt;

&lt;p&gt;A failed action tells the future agent something too:&lt;/p&gt;

&lt;p&gt;Don't blindly repeat it as the first recommendation.&lt;/p&gt;

&lt;p&gt;Making Memory Visible&lt;/p&gt;

&lt;p&gt;One thing we didn't want was a black-box interface where the agent magically produces a personalized response and the user has no idea why.&lt;/p&gt;

&lt;p&gt;The interface therefore includes a dedicated Hindsight Memory panel.&lt;/p&gt;

&lt;p&gt;For a customer like Rahul, the interface can show:&lt;/p&gt;

&lt;p&gt;Hindsight Memory&lt;/p&gt;

&lt;p&gt;Payment failure&lt;br&gt;
Previous payment issue was resolved&lt;br&gt;
by updating the PayFlow app.&lt;/p&gt;

&lt;p&gt;Previous support interaction&lt;br&gt;
Customer experienced a payment problem&lt;br&gt;
on an Android device.&lt;/p&gt;

&lt;p&gt;This gives the user a direct connection between the memory system and the response.&lt;/p&gt;

&lt;p&gt;It also makes debugging easier.&lt;/p&gt;

&lt;p&gt;If the agent produces an unexpected answer, we can inspect what memories were actually retrieved instead of guessing what context the model received.&lt;/p&gt;

&lt;p&gt;A Real Before-and-After Example&lt;/p&gt;

&lt;p&gt;The easiest way to understand the difference is to compare two interactions.&lt;/p&gt;

&lt;p&gt;First interaction&lt;br&gt;
Rahul:&lt;br&gt;
"My payment failed."&lt;/p&gt;

&lt;p&gt;Agent:&lt;br&gt;
"Let's troubleshoot your payment issue."&lt;/p&gt;

&lt;p&gt;At this point, the agent has no relevant previous experience.&lt;/p&gt;

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

&lt;p&gt;Clear cache → Failed&lt;/p&gt;

&lt;p&gt;Update PayFlow app → Successful&lt;/p&gt;

&lt;p&gt;That outcome is retained.&lt;/p&gt;

&lt;p&gt;Second interaction&lt;/p&gt;

&lt;p&gt;Later:&lt;/p&gt;

&lt;p&gt;Rahul:&lt;br&gt;
"My payment failed again."&lt;/p&gt;

&lt;p&gt;The agent recalls:&lt;/p&gt;

&lt;p&gt;Customer: Rahul&lt;br&gt;
Platform: Android&lt;/p&gt;

&lt;p&gt;Previous issue:&lt;br&gt;
Payment failure&lt;/p&gt;

&lt;p&gt;Previous failed action:&lt;br&gt;
Clear cache&lt;/p&gt;

&lt;p&gt;Previous successful action:&lt;br&gt;
Update PayFlow app&lt;/p&gt;

&lt;p&gt;The response can therefore prioritize the successful resolution:&lt;/p&gt;

&lt;p&gt;"Updating the PayFlow app resolved this issue for you&lt;br&gt;
before, while clearing the cache didn't. Let's check&lt;br&gt;
your app version first."&lt;/p&gt;

&lt;p&gt;The difference isn't that the second response contains more words.&lt;/p&gt;

&lt;p&gt;The difference is that previous experience changed the decision.&lt;/p&gt;

&lt;p&gt;One Useful Lesson: Memory Quality Matters&lt;/p&gt;

&lt;p&gt;The first version of our testing exposed an interesting problem.&lt;/p&gt;

&lt;p&gt;When we repeatedly inserted the same support outcome during testing, Hindsight naturally returned multiple highly similar memories.&lt;/p&gt;

&lt;p&gt;The model could still produce a useful response, but the memory panel became noisy.&lt;/p&gt;

&lt;p&gt;That taught us something important:&lt;/p&gt;

&lt;p&gt;Adding memory is not the same thing as designing good memory.&lt;/p&gt;

&lt;p&gt;A production system would need additional controls around duplicate experiences, customer isolation, memory lifecycle, and which outcomes deserve stronger consideration.&lt;/p&gt;

&lt;p&gt;Persistent memory creates a new engineering responsibility: deciding what should be remembered and how that memory should influence future decisions.&lt;/p&gt;

&lt;p&gt;What We Learned&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Outcomes Are More Useful Than Transcripts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A transcript tells us what people said.&lt;/p&gt;

&lt;p&gt;An outcome tells us what happened.&lt;/p&gt;

&lt;p&gt;For support systems, that distinction can be extremely valuable.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Failed Attempts Are Also Knowledge&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A failed troubleshooting action isn't useless data.&lt;/p&gt;

&lt;p&gt;If a particular action failed for the same issue, the future agent should know that.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Memory Needs to Be Observable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Showing recalled memories in the UI makes the system easier to understand and debug.&lt;/p&gt;

&lt;p&gt;It also makes it much easier to verify whether personalization is actually coming from memory.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Memory Should Be Part of the Architecture&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We didn't want memory to be a feature added after the chatbot was finished.&lt;/p&gt;

&lt;p&gt;The flow was designed around:&lt;/p&gt;

&lt;p&gt;Recall&lt;br&gt;
  ↓&lt;br&gt;
Reason&lt;br&gt;
  ↓&lt;br&gt;
Respond&lt;br&gt;
  ↓&lt;br&gt;
Retain&lt;br&gt;
  ↓&lt;br&gt;
Improve future context&lt;/p&gt;

&lt;p&gt;That changes how the application is structured from the beginning.&lt;/p&gt;

&lt;p&gt;Where This Can Go Next&lt;/p&gt;

&lt;p&gt;The current payment-support example is deliberately simple, but the architecture is not tied to payments.&lt;/p&gt;

&lt;p&gt;The same pattern can apply to many support environments where previous actions and outcomes matter.&lt;/p&gt;

&lt;p&gt;A support agent could accumulate experiences such as:&lt;/p&gt;

&lt;p&gt;Issue&lt;br&gt;
   ↓&lt;br&gt;
Environment&lt;br&gt;
   ↓&lt;br&gt;
Action&lt;br&gt;
   ↓&lt;br&gt;
Outcome&lt;br&gt;
   ↓&lt;br&gt;
Future recommendation&lt;/p&gt;

&lt;p&gt;The key is that the memory isn't valuable simply because it exists.&lt;/p&gt;

&lt;p&gt;It's valuable when the agent retrieves the right previous experience at the right time and uses it to change what it does next.&lt;/p&gt;

&lt;p&gt;That's the behavior we were trying to build.&lt;/p&gt;

&lt;p&gt;A support agent shouldn't have to rediscover the same solution every time a customer returns.&lt;/p&gt;

&lt;p&gt;It should be able to look back at what happened, understand what worked, avoid what didn't, and continue from there.&lt;/p&gt;

&lt;p&gt;The goal isn't an AI that remembers everything.&lt;/p&gt;

&lt;p&gt;It's an AI that remembers what matters.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
