DEV Community

Ryagalla Sharvani
Ryagalla Sharvani

Posted on

From Chatbot to Context-Aware Support Agent

The first version of an AI support system is easy to imagine.

A customer types a question. The application sends it to an LLM. The model generates an answer. The answer appears in the chat.

The difficult part starts when the customer comes back.

A real support interaction has history. Customers have already tried things. They have previous tickets. Their environment may be known. Some problems recur.

I built AgentIQ around that observation: the support agent should use more than the current message when deciding what to say next.

The Basic Architecture

The core AgentIQ workflow looks like this:

Customer
↓
Support Message
↓
Customer Identification
↓
Memory Retrieval
↓
Knowledge Retrieval
↓
LLM Context
↓
Personalized Response
↓
Conversation Persistence
↓
Memory Update

  const userMsgObj = {
  role: 'user',
  content: message,
  timestamp: new Date()
};

const assistantMsgObj = {
  role: 'assistant',
  content: agentResult.reply,
  timestamp: new Date(),
  memoryUsed: Boolean(agentResult.memoryUsed),
  memoriesRetrieved: agentResult.memoriesRetrieved || [],
  ticketId: agentResult.ticketCreated
    ? agentResult.ticketCreated.ticketId
    : null,
  escalated: Boolean(agentResult.escalated)
};

conversation.messages.push(
  userMsgObj,
  assistantMsgObj
);

await conversation.save();
Enter fullscreen mode Exit fullscreen mode

AgentIQ also persists the current conversation in MongoDB. This is separate from long-term Hindsight memory: MongoDB stores the conversation and support workflow state, while Hindsight is used to retrieve durable customer knowledge across interactions.

The LLM is still responsible for generating the response, but it does not operate in isolation.

Before generating an answer, the system can provide relevant customer history and support information.

That changes the role of the model.

Instead of answering:

"What does this message mean?"

the system can answer:

"Given this customer's current problem and relevant history, what is the most useful next response?"

Combining Memory With Knowledge

Customer memory and a knowledge base solve different problems.

The knowledge base answers:

What do we know about the product or issue?

Customer memory answers:

What do we know about this particular customer?

const kbResults = searchKnowledgeBase(userMessage);

let kbContext = '';

if (kbResults.length > 0) {
  kbContext =
    'SUPPORT POLICIES & KNOWLEDGE BASE RUNBOOKS:\n' +
    kbResults
      .map(article =>
        `[${article.topic} (${article.category})]: ${article.content}`
      )
      .join('\n');
}
Enter fullscreen mode Exit fullscreen mode

AgentIQ keeps this knowledge separate from customer memory. The knowledge base contains product and support procedures, while Hindsight contains information specific to the customer.

For example, a support article might explain how to troubleshoot an application crash.

Customer memory might say that this particular customer has already tried the first three steps.

The agent can therefore avoid sending the customer through the same checklist again.

The combined context becomes:

Current issue
+
Relevant product knowledge
+
Relevant customer history
+

Previous troubleshooting

Personalized support response

const systemPrompt = `
You are AgentIQ, an enterprise AI customer support specialist.

AUTHENTICATED CUSTOMER:
Name: ${user.name}
Environment: ${envSummary}

CUSTOMER MEMORY:
${memoryContextText}

SUPPORT KNOWLEDGE:
${kbContext}

CURRENT SUPPORT TICKETS:
${liveTicketsContext}

Use the available context to provide a
personalized and accurate support response.
`;
Enter fullscreen mode Exit fullscreen mode
const rawLlmResponse = await llm.callLLM({
  systemPrompt,
  messages: [
    ...formattedHistory,
    { role: 'user', content: userMessage }
  ],
  temperature: 0.2,
  responseFormat: { type: 'json_object' }
});
Enter fullscreen mode Exit fullscreen mode

The LLM does not directly query Hindsight or the knowledge base. The AgentIQ backend performs retrieval first and constructs a context-rich system prompt. Groq is then responsible for reasoning over that context and generating the response.

This separation became an important architectural decision in AgentIQ.

Hindsight as the Memory Layer

async function recall({ bankId, query = '', maxTokens = 2000 }) {
  const response = await hindsightClient.recall(
    bankId,
    query,
    {
      maxTokens,
      includeEntities: true
    }
  );

  const results = response?.results || [];

  return {
    memories: results,
    points: results.map(
      result => result.text || JSON.stringify(result)
    ),
    memoryUsed: results.length > 0
  };
}
Enter fullscreen mode Exit fullscreen mode

The bankId is important here. AgentIQ uses a separate memory bank for each authenticated customer, so a recall operation searches the relevant customer's history rather than a shared memory pool.

Hindsight is responsible for the persistent customer-memory part of this workflow.

Its per-user memory pattern is designed around isolated memory stores, allowing information about one user to remain separate from another user's context.

The system can retain useful information from support interactions and later recall relevant information when a new issue arrives.

 await hindsight.retain({
  bankId,
  content: aiParsed.memoryToRetain,
  metadata: {
    topic: aiParsed.ticketDetails?.category || 'Customer Knowledge',
    customerName: user.name
  }
});
Enter fullscreen mode Exit fullscreen mode

After the response is generated, AgentIQ can retain durable information such as a verified solution, customer environment detail, or recurring technical issue. This creates the recall → response → retain lifecycle used by the support agent.

That means the customer does not need to manually attach their entire support history to every conversation.

The Important Backend Step

async function processCustomerMessage({
  user,
  conversation,
  message,
  memoryEnabled = true
}) {
  const userMessage = (message || '').trim();

  // Each customer gets an isolated Hindsight memory bank
  const bankId =
    user.hindsightBankId || `bank_user_${user._id}`;

  // 1. Recall relevant customer memories
  let recalledPoints = [];

  if (memoryEnabled) {
    const recallResult = await hindsight.recall({
      bankId,
      query: userMessage
    });

    if (recallResult?.points?.length > 0) {
      recalledPoints = recallResult.points;
    }
  }

  // 2. Retrieve relevant support knowledge
  const kbResults = searchKnowledgeBase(userMessage);

  const kbContext = kbResults.length
    ? kbResults
        .map(k => `[${k.topic}]: ${k.content}`)
        .join('\n')
    : 'No matching knowledge-base article found.';

  // 3. Build the context given to the LLM
  const memoryContext = recalledPoints.length
    ? recalledPoints.join('\n')
    : 'No relevant customer memories found.';

  const systemPrompt = `
    You are AgentIQ, an AI customer support agent.

    Relevant customer memory:
    ${memoryContext}

    Relevant support knowledge:
    ${kbContext}

    Use the customer history and support knowledge
    to provide a personalized response.
  `;

  // 4. Generate the response using Groq
  const response = await llm.callLLM({
    systemPrompt,
    messages: [
      { role: 'user', content: userMessage }
    ],
    temperature: 0.2
  });

  return response;
}
Enter fullscreen mode Exit fullscreen mode

The important part is the order of operations. AgentIQ first identifies the customer's isolated memory bank, retrieves relevant memories from Hindsight, searches the support knowledge base, and only then sends the combined context to the LLM. The model therefore generates its response using both customer-specific history and product knowledge.

The important thing in this code is the order of operations.

The system should not blindly generate the response first and then look for memory.

Relevant memory needs to become part of the context used to generate the response.

Hindsight's documented recall/retain lifecycle follows the same general model: recall relevant information before the agent runs and retain useful information afterward.

A Simple Example

const recallResult = await hindsight.recall({
  bankId: user.hindsightBankId,
  query: "The browser is crashing again"
});

console.log(recallResult.points);
Enter fullscreen mode Exit fullscreen mode

Relevant customer memory:

  • Browser previously crashed repeatedly.
  • Customer cleared the browser cache.
  • Disabling a browser extension resolved the previous crash.

Current message

"The browser is crashing again."
        ↓
Hindsight Recall
        ↓
Previous troubleshooting
"Extension was disabled and fixed the issue."
        ↓
LLM Context
        ↓
Personalized response
"Since disabling the extension previously resolved this,
can you confirm whether that extension is enabled again?"
Enter fullscreen mode Exit fullscreen mode

Imagine that a customer previously reported a browser problem.

During the first interaction, they tried:

Restarting the browser
Clearing the cache
Disabling a browser extension

Disabling the extension solved the problem.

Later, the customer says:

"The browser is crashing again."

A generic chatbot might produce a standard troubleshooting list.

AgentIQ has additional context.

It can recognize that this is related to a previous issue and ask whether the previously successful solution has been reversed.

That is a small behavioral change, but it is exactly what persistent memory is supposed to accomplish.

Designing the Customer Experience

The memory should not become an implementation detail that customers never notice.

AgentIQ's interface therefore includes customer-context information alongside the support conversation.

The customer can see that the system understands relevant history rather than treating every conversation as a completely new interaction.

This also helps when an issue needs human support.

Instead of handing a staff member a blank ticket containing only:

const aiSummary = {
  problem: description,
  history: recalledPoints.join('; '),
  alreadyTried: contextHighlights.alreadyTried || [],
  environment: envSummary,
  previousSolutions: 'None verified yet in memory.',
  currentStatus:
    'Escalated by AgentIQ for human support desk inspection.',
  suggestedNextStep:
    'Verify service logs and customer environment.'
};
Enter fullscreen mode Exit fullscreen mode

When an issue is escalated, AgentIQ carries relevant memory, troubleshooting history, customer environment, and the current problem into the ticket. The human support engineer therefore receives context instead of starting from the customer's latest sentence alone.

"Application is crashing."

the system can provide:

Current problem:
Application crashes repeatedly.

Previous related issue:
Browser extension caused a similar problem.

Already attempted:
Cache cleared.

Previous successful solution:
Extension disabled.

Current status:
Issue has returned.

The staff member can start from the existing context.

What I Learned

The most useful lesson was that personalization is not the same as adding a customer's name to an answer.

A response saying:

"Hi Rahul, let's troubleshoot your issue."

is not meaningfully personalized.

A response that understands:

"You already tried these steps, and this problem previously had this resolution."

is.

The difference comes from context.

Another lesson was that retrieval quality matters. Storing large amounts of conversation history is not enough. The system needs to recover information that is relevant to the current problem.

Hindsight's documentation describes recall as combining retrieval approaches to surface relevant memory rather than requiring the agent to manually reconstruct its entire history.

The Limitation

Memory also creates a new responsibility.

If incorrect information becomes persistent memory, a future response could be influenced by that incorrect information.

That means a production system needs careful decisions around what becomes durable memory and how conflicting or outdated information is handled.

The goal is not to remember everything.

The goal is to remember the things that improve future decisions.

The Result

AgentIQ is therefore not just a chat interface connected to an LLM.

It is a workflow that combines:

Current conversation
+
Customer memory
+
Support knowledge
+
AI reasoning
+
Ticket history

The result is an agent that can continue a support relationship instead of treating every request as the customer's first interaction.

1. AgentIQ Support Chat

AgentIQ support chat

2. Knowledge Base Page

AgentIQ knowledge base page

3. Customer Context Sidebar

AgentIQ customer context sidebar

Resources

Top comments (0)