Introduction
The customer service industry is undergoing a quiet revolution. Not the kind where AI replaces human agents, but the kind where AI sits alongside them, whispering the right answer at the right moment. The era of the AI copilot has arrived, and it changes the economics of support from the inside out.
This article tells the engineering story behind building a specialized Customer Support Copilot Agent for a Thai insurance call center. Not a chatbot that talks to customers. Not a generic LLM wrapper that "kind of works." A purpose-built background agent that listens to live conversations, executes tool calls against real policy databases, and surfaces precisely the right suggestion to the human agent in Thai, in real time, with zero customer visibility.
What makes this project distinct is not just the agent itself, but the rigorous engineering methodology behind it: test-driven development from day one, automated evaluation across 30+ insurance operation categories, and a multi-agent prompt optimization pipeline built on the ROAD framework (Reflective Optimization via Automated Debugging). We started by defining what "correct" looks like, then built backward from there.
This is the story of that journey, from identifying the pain points that motivated the project, through architecture and test design, to the evaluation framework that made it measurable, and the optimization pipeline that made it better.
Pain Point in Business or Application
The Reality of Insurance Call Centers
Insurance customer support is uniquely demanding. A single agent handles policy inquiries, premium payments, claims processing, beneficiary changes, loan eligibility, document requests, and complaint escalations, often within the same call. Each operation requires navigating different systems, verifying identities, and following strict compliance workflows.
The consequences of getting it wrong are severe:
- Slow response times: Agents manually search across CRM systems, policy databases, and claim trackers while the customer waits on hold.
- High cognitive load: A typical agent juggles 30+ distinct operation types, each with its own verification requirements and decision trees.
- Error-prone manual lookups: Misidentifying a policy number format (is "4903022066" a policy number or a phone number?) leads to failed lookups and frustrated customers.
- Agent burnout: Repetitive verification workflows - "Please provide your date of birth," look up policy, verify identity, retrieve details, drain agents who handle 80+ calls per day.
- Compliance risk: Missing a verification step or providing unconfirmed information (hallucinated reference numbers, estimated callback times) creates regulatory exposure.
Why a Generic LLM Wasn't Enough
Early experiments with off-the-shelf LLMs revealed a fundamental mismatch. A generic model would:
- Generate conversational text when the system needs tool calls. The copilot must output structured function invocations (
find_policy_by_number(policy_number="4903022066")) rather than natural language responses. - Hallucinate data: inventing policy numbers, claim amounts, or reference codes that don't exist in the database.
- Skip verification steps: jumping directly to task execution without identity verification, violating the Read-Before-Write protocol.
- Lose ordering discipline: executing tool calls in the wrong sequence (e.g., attempting a beneficiary change before retrieving current beneficiary information).
- Mix languages: generating English responses when all customer-facing suggestions must be in Thai.
The gap between "an LLM that can talk about insurance" and "an agent that can reliably execute insurance workflows" is enormous. Bridging that gap required a specialized system prompt, a structured tool framework, and critically a way to measure whether the agent was actually doing the right thing.
Our Solution
Architecture Overview
The Copilot Agent is a background process that operates invisibly during live calls. It has no direct interaction with the customer, it only communicates with the human agent through tool calls that surface as suggestion cards in the agent's UI.

The agent is powered by … and constrained by an extensively engineered system prompt that enforces:
- Echo-Sandwich Protocol: Before any database lookup, emit a
suggest(msg="กรุณารอสักครู่...") ("Please wait..."). After retrieval, immediately announce the result. This ensures the human agent always knows what the AI is doing. - Read-Before-Write Protocol: Never execute a mutation (cancellation, beneficiary change, loan processing) without first retrieving the current state. No blind writing.
- Atomic Step Discipline: Each suggestion contains exactly one piece of information. "Policy found for วิชัย สมบูรณ์" and "Please provide date of birth for verification" are separate tool calls and never combined.
The Test-Driven Approach
Before writing a single line of agent logic, we defined what correct behavior looks like. This is the foundation that made everything else possible.
Each test case is a structured scenario with:
- A conversation history (alternating customer and agent messages in Thai)
- An expected output (the exact sequence of tool calls the agent should produce)
For example, a beneficiary change scenario:
Topic: เปลี่ยนผู้รับผลประโยชน์ (Beneficiary Change)
Conversation:
Customer: "กรมธรรม์เลขที่ 4663466284 ค่ะ อยากเปลี่ยนผู้รับผลประโยชน์ค่ะ"
Agent: "ขอยืนยันตัวตนด้วยวันเดือนปีเกิดนะคะ"
Customer: "15 มีนาคม 2523 ค่ะ"
Customer: "อยากเปลี่ยนเป็น นางสาวสมใจ แก้วมณี เป็นภรรยาค่ะ"
Expected Output:
1. verify_identity(method=\"dob\")
2. get_beneficiary(policy_number=\"4663466284\")
3. submit_beneficiary_change_request(...)We built 30+ topics with multiple test cases each, covering the full spectrum of insurance operations: policy inquiries for tax preparation, simple claims, member card requests, policy surrenders, loan applications, complaint escalations, and more. The test cases are stored in a processed CSV with structured JSON conversation histories:
topic,input,expected_output
เปลี่ยนผู้รับผลประโยชน์,"[{""role"":""system"",...}, ...]","['verify_identity(method=""dob"")', 'get_beneficiary(...)']"This test-first methodology gave us three superpowers:
- Objective measurement: Every system prompt change produces a number. No more "it seems better."
- Regression detection: If an optimization improves claims processing but breaks identity verification, the test suite catches it immediately.
- Failure classification: When a test fails, we know exactly what went wrong for example: missing tools, wrong parameters, incorrect sequencing, or hallucinated actions.
Evaluation, Benchmarking, and Optimization
Dual-Metric Scoring
Our evaluation scores each test case on two dimensions: sequence accuracy (did the agent call the right tools in the right order, via SequenceMatcher) and argument accuracy (did it pass the correct parameters). For structured fields like policy numbers, we use exact matching. For free-text suggestions in Thai, we use an LLM judge to assess semantic equivalence — it recognizes that "พบกรมธรรม์ของคุณวิชัย สมบูรณ์" and "กรมธรรม์เลขที่ 4903022066 ชื่อ วิชัย สมบูรณ์" convey the same intent despite different wording.
Baseline result
Our initial evaluation across 29 test cases in 5 task categories revealed a clear pattern:
| Task Category | Accuracy |
|---|---|
| Medical Claim Submission | 95.46% |
| Claim Status Tracking | 95.28% |
| Claim Rejection Complaint | 84.17% |
| Member Card Request | 82.98% |
| Policy Surrender | 75.62% |
Simple single-step workflows achieved 95 to 100 percent, while complex multi-step flows involving identity verification and data retrieval fell to 36 to 60 percent. The agent consistently struggled with specific workflow compositions rather than failing at random.
The ROAD framework
To improve the agent systematically, we introduced the ROAD framework (Reflective Optimization via Automated Debugging), a multi-agent pipeline that automates the debug, analyze, and optimize cycle:
- Filter & Classify: Detect failures (accuracy < 85%), then classify each as agent-side or user-side. Then discard user-side failures (ambiguous input, missing context), because optimizing for them is counterproductive.
- Cluster & Analyze: Group agent-side failures by structural error signatures (missing tools, extra tools, wrong parameters, wrong sequence) using lightweight heuristics. This reduces N individual LLM analysis calls to K cluster-level calls. Rank each cluster by impact:
count × (1.0 - avg_accuracy). - Optimize: Provide the analysis reports along with the current system prompt to the Optimizer. This step is critical, because early versions generated protocols from scratch and caused severe prompt drift. The remedy is to make only incremental improvements.
- Evolve: Replace only the protocol section of the system prompt (the part marked by the headers
# Interaction Workflowsor# Operational Protocol), while preserving all other instructions.
Results
We executed the ROAD pipeline across nine separate optimization runs totaling 40 iterations, progressively refining both the pipeline and the system prompt. Each run used an 80/20 train/test split:
| Run | Iterations | Initial Accuracy | Best Accuracy | Holdout Accuracy |
|---|---|---|---|---|
| 1 | 10 | 68.89% | 68.89% | 72.28% |
| 2 | 2 | 69.27% | 69.27% | 70.91% |
| 3 | 2 | 78.53% | 78.53% | 70.40% |
| 4 | 2 | 75.93% | 75.93% | — |
| 5 | 1 | 77.70% | 77.70% | — |
| 6 | 1 | 68.99% | 68.99% | — |
| 7 | 2 | 68.99% | 68.99% | 67.86% |
| 8 | 10 | 81.24% | 83.73% | — |
| 9 | 10 | 85.06% | 85.14% | 79.65% |
The trajectory is clear. Early runs (1 to 3) stalled because the pipeline had bugs, including code-block fences in saved prompts and an optimizer that rewrote from scratch instead of making incremental changes. Runs 4 to 7 were shorter experiments conducted while we fixed the pipeline. Once the pipeline was stable, Runs 8 to 9 showed real improvement: +2.49% in Run 8 and a final best of 85.14% with 79.65% holdout accuracy in Run 9.
A key takeaway is that the first optimization pass in each run captured the highest-impact fixes, while later iterations showed diminishing returns and some oscillation, since fixes for one failure cluster sometimes caused regressions in others.
Concrete Fixes Discovered
The pipeline identified and fixed four specific patterns:
- Digit-Length Routing: The agent confused policy numbers, phone numbers, and national IDs. Fix: 13 digits → National ID, 10 digits starting with '0' → phone, 10 digits not starting with '0' → policy number.
- Verify Identity Method: Agent used
method="national_id"when the customer clearly provided a date of birth. Fix: explicit routing rule in the prompt. - Transfer Tool Disambiguation: Agent called
transfer_callinstead oftransfer_to_human_agentsfor complaint escalations. - Mandatory Referral List: Operations like address changes and credit card payment changes must be referred to the 1373 hotline, now explicitly enumerated.
Conclusion
We showed that the jump from an LLM that understands insurance to a system that reliably executes workflows is achievable with disciplined engineering. Test-driven development gave objective quality signals, dual-metric scoring captured both structure and content, and the ROAD framework turned prompt work into an automated, measurable loop.
ROAD delivered most of its value in the first pass by surfacing high-impact failure patterns; later passes had diminishing returns and occasional regressions. Stability improves by separating agent-side from user-side errors, clustering before analysis, and making incremental fixes to prevent prompt drift.
Looking ahead:
- Conflict-aware optimization that detects rule collisions
- Topic-specific protocol routing instead of one monolithic prompt
- Real-time evaluation tied to production data
- Broader tool coverage with automated test generation
Core lesson: building the agent is 20% architecture and 80% evaluation. Reliability comes from tests that flag errors, scores that quantify them, and a pipeline that explains and fixes root causes.
Collaborate and partner with our AI Lab at Amity Solutions here


