DEV Community

Madhuri
Madhuri

Posted on

My AI Support Agent Kept Forgetting Customers — Hindsight Fixed That

My AI Support Agent Kept Forgetting Customers — Hindsight Fixed That

The first version of my customer support agent had a simple but frustrating problem: every new conversation felt like starting from zero.

A customer could explain an issue, come back later, and the agent would have no useful context about what happened before. The customer had to repeat themselves.

I wanted to solve that with long-term memory, so I built MemorySupport, a small AI customer support agent using Hindsight as its memory layer.

The goal was simple:

Let the support agent remember what a customer had already told it.

The Problem: Every Conversation Started From Zero

A normal chat-based support flow can look like this:

Customer → Message → AI → Response
Enter fullscreen mode Exit fullscreen mode

The problem appears when the customer returns later.

For example:

Customer:
"My laptop keyboard is not working properly."

AI:
"Please try restarting your laptop..."
Enter fullscreen mode Exit fullscreen mode

Later:

Customer:
"The keyboard issue is still happening."
Enter fullscreen mode Exit fullscreen mode

Without memory, that second message doesn't contain enough information by itself.

The agent may not know:

  • What device the customer was talking about
  • What the original problem was
  • Whether troubleshooting was already attempted
  • Whether this is a continuing issue

That is where I wanted memory to become part of the architecture rather than just adding previous chat messages into a prompt.

Building MemorySupport

I kept the first version intentionally small.

The application has:

  • A customer name field
  • A support message field
  • A Hindsight memory bank for each customer
  • Memory retrieval
  • Memory storage
  • A simple support response

The basic architecture is:

             Customer
                 |
                 v
          Streamlit UI
                 |
          +------+------+
          |             |
          v             v
      Hindsight      New Message
       Recall            |
          |              |
          v              |
   Previous Memory       |
          |              |
          +------+-------+
                 |
                 v
          Support Response
                 |
                 v
          Hindsight Retain
Enter fullscreen mode Exit fullscreen mode

The important part is that Hindsight sits between the conversation and the application's long-term memory.

I used the Hindsight documentation to work with memory retention and recall.

Giving Each Customer Their Own Memory

The first design decision was figuring out how to separate customers.

For the prototype, I created a memory bank based on the customer's name:

bank_id = (
    "customer-"
    + customer.strip().lower().replace(" ", "-")
)
Enter fullscreen mode Exit fullscreen mode

So if the customer is Madhuri, the memory bank becomes:

customer-madhuri
Enter fullscreen mode Exit fullscreen mode

This means conversations don't all get mixed into one memory space.

For a production application, I would use a permanent customer ID from the authentication or customer database instead of a name.

Using Hindsight to Remember

The two operations that became central to my implementation were recall and retain.

First, I retrieve information relevant to the customer's current message:

memories = client.recall(
    bank_id=bank_id,
    query=message
)
Enter fullscreen mode Exit fullscreen mode

Then I store the new interaction:

client.retain(
    bank_id=bank_id,
    content=f"Customer {customer} said: {message}",
    context="Customer support conversation"
)
Enter fullscreen mode Exit fullscreen mode

I think of these as two different jobs.

Recall asks:

What do I already know that might matter right now?

Retain asks:

What should I remember from this conversation?

That separation made the system much easier to understand.

The Test That Made the Difference

The most useful test was extremely simple.

I entered:

Customer: Madhuri

"My laptop keyboard is not working properly."
Enter fullscreen mode Exit fullscreen mode

The interaction was stored in Hindsight.

The memory displayed:

Madhuri reports that her laptop keyboard is not working properly.
Enter fullscreen mode Exit fullscreen mode

Then I sent another message from the same customer:

"The keyboard issue is still happening."
Enter fullscreen mode Exit fullscreen mode

This time, Hindsight retrieved the earlier information.

The application could now connect:

Current message:
"The keyboard issue is still happening."

+

Previous memory:
"Madhuri reports that her laptop keyboard is not working properly."
Enter fullscreen mode Exit fullscreen mode

The support agent could respond with context:

Hi Madhuri! I remember your previous conversation.
I can use that information to better understand your
current issue and continue helping you.
Enter fullscreen mode Exit fullscreen mode

That was the moment the project actually started feeling different from a normal chatbot.

The second conversation wasn't completely new anymore.

Before vs After

The difference can be summarized like this.

Without memory

Customer:
"The keyboard issue is still happening."

AI:
"What issue are you experiencing?"
Enter fullscreen mode Exit fullscreen mode

The customer has to explain it again.

With Hindsight

Customer:
"The keyboard issue is still happening."

Hindsight:
"Previous keyboard problem found."

AI:
"I remember your previous conversation..."
Enter fullscreen mode Exit fullscreen mode

The agent can continue from existing context.

It's a small example, but it demonstrates why persistent memory can matter in customer support.

Keeping the Memory Layer Separate

One thing I wanted to avoid was putting all the memory logic directly inside the UI.

The Hindsight client is initialized separately:

client = Hindsight(
    base_url="http://localhost:8888"
)
Enter fullscreen mode Exit fullscreen mode

The Streamlit application handles the interface.

Hindsight handles the memory operations.

That separation gives the project room to grow.

The same memory layer could eventually be used by a web application, customer-support dashboard, API, or automated support agent.

Hindsight's agent memory capabilities helped me think about memory as a separate system component rather than just another prompt variable.

The Part That Didn't Go Smoothly

The integration wasn't completely straightforward.

At one point, I experimented with asynchronous calls and multiple event-loop executions. That resulted in:

RuntimeError:
This event loop is already running
Enter fullscreen mode Exit fullscreen mode

I then tried changing the execution approach, which led to another event-loop error involving a closed loop.

This was a useful debugging lesson because the problem wasn't actually my memory design.

There were two separate concerns:

Memory architecture
        +
Python execution model
Enter fullscreen mode Exit fullscreen mode

Mixing those together made the problem harder to understand.

I eventually simplified the implementation and kept the Hindsight service running separately from the Streamlit application.

The local setup became:

Terminal 1
    |
    v
Hindsight API
localhost:8888
    ^
    |
    | HTTP
    |
    v
Terminal 2
    |
    v
Streamlit
MemorySupport
Enter fullscreen mode Exit fullscreen mode

That separation made debugging much easier.

A Small Prototype, but a Bigger Lesson

One thing I learned from this project is that a chat transcript and memory are not necessarily the same thing.

A transcript answers:

What did the customer say?

Memory tries to answer:

What information from the customer's history is relevant now?

That difference becomes important when conversations become longer.

Imagine a customer has contacted support ten times.

You don't necessarily want to send every previous message into every new request.

You want to find the information that actually matters.

That's where a memory layer becomes useful.

What I Would Change for Production

The prototype intentionally keeps things simple.

For a real customer-support system, I would change several things.

1. Use a real customer ID

Names aren't reliable identifiers. I would use a permanent customer ID from the application's identity system.

2. Add authentication

Customer memory should only be accessible to authorized users or systems.

3. Add memory-management policies

A production system needs clear rules for:

  • What information is stored
  • How long it is stored
  • Who can access it
  • How information can be corrected
  • How information can be deleted

4. Store richer support information

Instead of only storing:

"My keyboard is not working."
Enter fullscreen mode Exit fullscreen mode

the system could eventually remember:

Issue: Keyboard not working
Device: Laptop
Status: Unresolved
Previous action: Restarted device
Enter fullscreen mode Exit fullscreen mode

That could make future support interactions more useful.

What I Learned From Building It

Start small

I didn't need a complicated multi-agent system to prove the memory concept.

One customer, one recurring problem, and one recall operation were enough.

Recall and retain are different

Separating retrieval from storage made the application easier to reason about.

Order matters

I wanted the application to retrieve existing information before saving the new message.

That keeps the current request separate from the memory it is about to create.

Infrastructure matters

A memory system can work correctly while the application still fails because the memory service isn't running.

Keeping the Hindsight service separate made this much easier to debug.

Memory should be treated as a system component

Instead of thinking:

AI + prompt
Enter fullscreen mode Exit fullscreen mode

I started thinking:

AI
+
Memory
+
Application
Enter fullscreen mode Exit fullscreen mode

That is a more useful architecture for applications where conversations need continuity.

Where I Want to Take It Next

The next version of MemorySupport could make the retrieved memory more structured.

For example, the agent could distinguish between:

  • Previous unresolved issues
  • Resolved issues
  • Customer preferences
  • Previous troubleshooting steps
  • Product information
  • Support history

The support agent could then use those memories to provide more contextual responses.

The flow would remain simple:

New Customer Message
        |
        v
Retrieve Relevant History
        |
        v
Use History as Context
        |
        v
Generate Response
        |
        v
Remember New Interaction
Enter fullscreen mode Exit fullscreen mode

The goal isn't simply to make an AI answer questions.

It's to make the conversation continuous.

Conclusion

My AI support agent started with a simple problem: it forgot customers between conversations.

Using Hindsight, I turned memory into an explicit part of the application.

The system can retain customer interactions, recall relevant history, and use that context when the customer returns.

The implementation is still a prototype, and there are plenty of things I would change before putting it into production.

But the core idea works.

A customer says something once.

The system remembers it.

The customer comes back later.

The conversation can continue from there.

For me, that was the biggest takeaway from building MemorySupport:

A useful support agent shouldn't just answer the current message. It should understand where that message came from.


Top comments (0)