Skip to content

Groupe Mutuel · Aug 2025 – Feb 2027 · core contributor, harness built solo

Conversational agentic systems, and their evaluation

EVA is the conversational agent of Groupe Mutuel, a Swiss health insurer. In the mobile app, it answers policyholders about what their plan covers, in four languages. And I built the harness that proves it answers right, every time.

Python · FastAPI · LLMs · Langfuse · Databricks · Kubernetes · React / TS

The situation

EVA is multi-agent, multi-turn, in four languages, across dozens of products and plan levels. An answer that is right for one level can be wrong for another. The old check looked at one answer, one message, once. Models changed often, with no reliable way to catch regressions.

The system

1 · Channel

channel

Mobile app

iOS and Android. Where 115,000 policyholders ask their questions.

backend

API

FastAPI, async Python. Answers are streamed.

2 · Brain

reasoning

Azure OpenAI

The GPT models every agent runs on.

knowledge

Azure AI Search

General terms, business rules, knowledge base.

memory

Azure Blob Storage

The history of every conversation.

EVA

● Guardrails and language detection first (my work). Then a router calls 0 to n of 7 specialised agents, in parallel, and a synthesis agent writes one answer in the policyholder's language.

questionroutercoveragetherapists+ 5 moresynthesisanswer

7 agents: coverage · therapists · self-service · contact · info · premiums · offers

business system

Policy API

Deductible, plan, premiums, invoices.

policyholder data

Database

The source of truth.

3 · Steering

observability (my work)

Langfuse

Every LLM call, agent and tool traced, with cost and latency.

evaluation (my work)

The harness

Simulated policyholders, calibrated judges, pass^k. Gates feature rollouts.

data (my work)

Databricks

Nightly ETL of the traces; questions grouped by topic with BERTopic.

improvement

Expert review

Business experts review conversations and flag errors; dashboards in Power BI.

4 · Foundation

runtime

Azure Kubernetes Service

Everything above runs here, in Docker containers.

delivery

GitLab CI/CD

Lint, types, tests, images. Dev → int → staging → prod, plus a preview per branch.

health (my work)

Golden questions

A pod stays out of rotation until its latency is back under the threshold.

● my work. After the Groupe Mutuel poster, Oct 2026; internal names left out.

Each question goes through guardrails, then a router that calls zero to n specialised agents in parallel, then a synthesis agent that answers in the policyholder's language. A coverage question takes about ten LLM calls, and every call is traced with its cost and latency. We shipped 25 releases of this architecture in about 14 months.

The harness

1 · Dataset

situations

125 situations

One YAML file each: a goal, a contract, a persona, tags. Played with every relevant product, plus one that covers nothing.

personas

8 personas, 4 languages

Different ways of asking. Facts are only revealed when EVA asks for them.

2 · Simulation

Simulated policyholder ⇄ EVA

An LLM plays the policyholder and talks, turn after turn, with the real EVA. N situations × k runs, in parallel.

goalcontractpersonaconversation, turn after turn× k runsquestionanswersimulatedpolicyholderEVAthe real oneend of turncontinuegoal agentachieved · failedtrace

goal agent

Knows when to stop

After each turn it checks whether every part of the goal got an answer. A turn limit stops the rest.

output

conversations.jsonl

Messages, EVA's steps and the goal agent's decision. Kept, so they can be judged again without simulating again.

3 · Evaluation

The LLM classifies, the code scores

Each use case has its evaluators. LLM judges give a typed verdict per claim; they are calibrated on human labels before their scores count.

conversationfaithful?noexcludedcode checksLLM judgeverdictscodescorehuman reviewpass / fail× k runspass^k

control

Faithfulness check

If the simulated policyholder invented a fact, the conversation is excluded, not judged.

code

Checks and scoring

Which agents were called, whether the goal was reached; then a penalty table turns the judges' verdicts into a score.

humans

Review

A reviewer can overturn a verdict; the score is recomputed without calling the LLM again.

4 · Results

per use case

pass@k and pass^k

A run passes when its score clears the threshold with no critical error. Over k runs: at least once, or every time.

interface

Evaluation Lab

Runs, conversations and verdicts in one place. Arena compares two deployments blind.

production

Release gate

A new feature reaches policyholders only once its use cases hold.

After the thesis deck. Every run is reproducible: commit, code and document fingerprints, dataset hash. 219 tests. Built alone in about six weeks.
  • A simulated policyholder with a goal, a persona, and facts it only reveals when asked.
  • Each situation is played with every relevant product, a level that doesn't cover it, and a product that covers nothing, so refusals are tested as much as answers.
  • Judges are calibrated before their scores count. Every run is reproducible: code, documents and dataset are fingerprinted.

Chance of passing, for an agent that succeeds 70 % of the time

Illustration (p = 0.7), not production results

Chance of passing, for an agent that succeeds 70 % of the time
kpass@k, at least one successpass^k, all succeed
k = 170 %70 %
k = 291 %49 %
k = 397 %34 %
k = 499 %24 %
k = 5100 %17 %
pass@k
At least one of k runs passes. It climbs fast: 100 % at k = 5. That is what a demo shows.
pass^k
All k runs pass. It falls just as fast: 17 % at k = 5. That is what a policyholder who asks again expects.

The harness runs each situation k times and reports both, per use case.

Results

policyholders have used EVA
115,000
have access to it in the app
400,000+
calls avoided in 6 months
~18,000
estimated savings
≈ CHF360k

Groupe Mutuel, 2026. Savings are an internal estimate; run scores stay internal.

The harness itself: 219 tests, 125 situations × 30 products, 4 languages, 8 personas, built solo in about six weeks. It catches regressions and gates feature rollouts in production.

Try it

A real test situation from the harness. The simulated policyholder knows things EVA has to ask for, then judges check every claim of the answer.

Harness situation, anonymised. The policyholder is simulated.

  1. simulated policyholderI need to replace an old crown. Does my insurance pay for it?
  2. EVAIt depends on why it needs replacing. Was it caused by an accident, or by a cavity?
  3. simulated policyholderA cavity. My dentist estimates about CHF 2,500.
  4. EVABasic insurance doesn't cover dental care after a cavity. Your dental supplement pays part of it, up to its yearly limit. Do you want the details of your plan?

Trajectory

  1. 1. guardrails, language detected: English
  2. 2. router → coverage agent
  3. 3. coverage agent: basic insurance, dental supplement
  4. 4. synthesis → answer

Judges

  • Asked for the cause before answeringexpected
  • Basic insurance doesn't cover care after a cavitycorrect
  • The dental supplement pays part of itcorrect

Goal met in 2 turns.

The same question, replayed 5 times

Each try succeeds 70 % of the time. Replay to roll again.

  1. Try 1: pass
  2. Try 2: pass
  3. Try 3: fail
  4. Try 4: pass
  5. Try 5: pass
pass@5
pass: one success is enough
pass^5
fail: all five must pass

What I learned

The judges were wrong before EVA was: calibration showed they flagged the standard texts EVA adds to its answers as unsourced. We fixed the judges before trusting a single score.

Next