Terry Henrard

portfolioTerry HenrardMarch 19, 2025Updated November 24, 20255 minAIRAGVector DBAzure OpenAIAzureQDrant.NET 9C#Customer SupportHuman-in-the-LoopIngestionOCRRerankingEmbeddingsReactTypeScriptMulti-Model RoutingStreamingVector SearchB2C

The "Firehose" Problem

Imagine being the only person standing between a mountain of customer inquiries and a peaceful day at the office. That was the reality for the customer service lead at Thomas & Piron during peak activity periods.

The phone wouldn't stop ringing, the inbox was overflowing, and frustration was mounting—both for the customers waiting for answers and the team trying to provide them. High churn was becoming a real threat, and burnout was looming.

We needed a solution. Not just a band-aid, but a digital reinforcement.

Contents

Enter the AI Agent

We didn't just build a chatbot; we built a capable digital assistant. This agent wasn't designed to replace the human touch but to handle the heavy lifting so the human team could focus on what really matters.

Core Capabilities

Polyglot Genius

The agent understands natural language in English, French, Dutch, and more. No more language barriers standing in the way of support.

Deep Knowledge (RAG)

For simple queries, it performs Retrieval-Augmented Generation (RAG) on internal documentation, instantly finding answers buried in PDFs or manuals.

Human-in-the-Loop

For complex or sensitive actions, the agent pauses and asks for human approval. It prepares the work, but you pull the trigger.

Action Oriented

It doesn't just talk; it does. It can create tickets directly in the CRM and schedule calls in the human agent's calendar.

Code Highlight: The "Human-in-the-Loop" Pattern

One of the most critical features was ensuring the AI didn't go rogue. Here is a simplified snippet of how we defined a Semantic Kernel function that requires human approval before finalizing an action.

[KernelFunction, Description("Schedules a meeting with a human agent.")]
public async Task<string> ScheduleMeetingAsync(
    [Description("The email of the customer")] string customerEmail,
    [Description("The preferred date and time")] DateTime preferredTime
)
{
    // 1. Check availability
    if (!await _calendarService.IsAvailableAsync(preferredTime))
    {
        return "Slot not available. Please suggest another time.";
    }
 
    // 2. Create a 'Pending' appointment requiring approval
    var appointmentId = await _crmService.CreatePendingAppointmentAsync(
        customerEmail,
        preferredTime,
        requiresApproval: true
    );
 
    // 3. Notify the human agent
    await _notificationService.SendApprovalRequestAsync(appointmentId);
 
    return $"Meeting request created (ID: {appointmentId}). Waiting for agent approval.";
}

Under the Hood: The Tech Stack

I served as the Full-Stack Developer on this project, handling everything from the React frontend to the .NET backend. Here is the arsenal we used:

Azure OpenAI ServicesReact (TypeScript).NET 9 (C#)QDrant (Vector DB)Azure Cloud

The "Brain" (RAG Pipeline)

Building a RAG system that actually works is more than just throwing text into a database. We had to get creative with ingestion and retrieval.

// Example of the retrieval pipeline with reranking
public async Task<List<DocumentChunk>> RetrieveAndRerankAsync(string userQuery)
{
    // 1. Vector Search (Recall)
    var embedding = await _embeddingGenerator.GenerateEmbeddingAsync(userQuery);
    var initialResults = await _qdrantClient.SearchAsync(embedding, limit: 20);
 
    // 2. Reranking (Precision)
    // We use a cross-encoder model to score relevance between query and documents
    var rerankedResults = await _reranker.RerankAsync(userQuery, initialResults);
 
    // 3. Filter and Return Top K
    return rerankedResults
        .Where(r => r.RelevanceScore > 0.75)
        .Take(5)
        .ToList();
}

The Impact

The results spoke for themselves. By deploying this agent, we managed to turn the tide during peak season.

30%Customer Tickets Automated60%Workload Reduction (Peak)

Conclusion

This project wasn't just about using the latest AI buzzwords; it was about solving a real human problem with technology. We took a stressed-out support process and injected it with intelligence, efficiency, and a bit of .NET 9 magic.

Now, the customer service lead can actually take a lunch break. đŸ¥ª

Inspired by this project?

I can help you build something similar — let's chat about your idea and the next steps.

Subscribe to my newsletter

Get updates about new projects and occasional tips and tricks — just useful stuff.

Read another project

If you'd like to explore more, here's another project you might enjoy.