Quick start

This page walks through a complete simulation, one piece at a time. By the end you will have run a nurse ↔ patient dialogue and inspected the triage decision the nurse arrived at.

Before starting, make sure you have installed TriageSim and set your API key.

1. Define persona files

Personas are plain YAML lists. Create two small files to start with:

patient.yaml
- age_group: adult
  gender: female
  ethnicity: Australian
  socioeconomic_status: middle
  language_proficiency: high
  recall_accuracy: high
  cognitive_state: clear
  trust_in_healthcare: high
  pain_expression: moderate
  reactivity_to_clinician_emotion: low
  emotion_regulation: stable
  disfluency_rate: low
  topic_drift: low
  verbosity: medium
nurse.yaml
- gender: female
  ethnicity: Australian
  experience_level: senior
  risk_tolerance: low
  guideline_adherence: high
  communication_style: direct
  verbosity: medium
  emotional_expression: neutral

Every field is a free-form string, which is what lets you introduce new categories without changing the schema. See Personas for the full field reference.

2. Load and sample personas

from triagesim.personas import (
    load_patient_personas,
    load_nurse_personas,
    sample_patient_personas,
    sample_nurse_personas,
)

patients = load_patient_personas("patient.yaml")
nurses = load_nurse_personas("nurse.yaml")

patient_persona = sample_patient_personas(patients, k=1, seed=42)[0]
nurse_persona = sample_nurse_personas(nurses, k=1, seed=42)[0]

Passing a seed fixes which personas are drawn, so the same seed always selects the same pair from a larger pool.

3. Define the ground truth

This is the structured record the simulation is grounded in. Neither agent can see it. The patient agent is told only its chief complaint and pain score; the nurse agent starts with nothing and must elicit everything.

ground_truth = {
    "chiefcomplaint": "Syncope",
    "vitals": {
        "temperature": 99.1,
        "heartrate": 112,
        "resprate": 26,
        "o2sat": 91,
        "sbp": 98,
    },
    "acuity": 2,
    "pain": 7,
}

The acuity field is the reference triage level used for scoring. The five keys under vitals are the only vitals the nurse can check.

4. Create the LLM backends

Each backend is bound to a single output schema, so the nurse and patient need one each:

from triagesim.agents import OpenRouterLLM
from triagesim.core import NurseOutput, PatientOutput

model = "anthropic/claude-sonnet-4-5"

patient_llm = OpenRouterLLM(model_name=model, output_type=PatientOutput)
nurse_llm = OpenRouterLLM(model_name=model, output_type=NurseOutput)

The two backends can use different models if you want to study asymmetric pairings.

5. Create the agents

from triagesim.agents import NurseAgent, PatientAgent

patient = PatientAgent(llm=patient_llm, persona=patient_persona)
nurse = NurseAgent(llm=nurse_llm, persona=nurse_persona, algorithm="esi")

algorithm selects the triage protocol the nurse reasons with — "esi" for the Emergency Severity Index or "ats" for the Australasian Triage Scale. Both produce a level from 1 to 5, but the reasoning prompt differs.

6. Run

from triagesim import TriageRunner, RunnerConfig

config = RunnerConfig(max_turns=20, store_backend="memory", seed=42)

runner = TriageRunner(
    nurse_agent=nurse,
    patient_agent=patient,
    ground_truth=ground_truth,
    config=config,
)

artifact = runner.run()

Start small

max_turns defaults to 6. Each turn is at least two model calls, so raise it deliberately — a 20-turn run costs roughly three times a 6-turn one.

7. Inspect the result

run() returns a dictionary describing everything that happened:

print(artifact["run_id"])

for turn in artifact["history"]:
    print(turn)

final = artifact["trace"][-1]
print(final["action"]["triage"], final["action"]["explanation"])

See Run artifacts for the complete structure.

8. Score it

Because the ground truth is known, the run is scorable straight away:

from triagesim.utils import compute_all_metrics

metrics = compute_all_metrics(
    trace=artifact["trace"],
    belief=artifact["belief"],
    ground_truth=ground_truth,
)

print(metrics["triage"]["correct"])
print(metrics["triage"]["absolute_error"])

Evaluation metrics documents every value returned.

Next steps

  • Understand the loop — how the environment, belief state and nurse micro-turns fit together.

    Core concepts

  • Vary the population — build larger persona pools and filter them into experimental conditions.

    Personas

  • Scale up — persist runs to Redis instead of process memory.

    Running a simulation