Multi-speaker spoken dialogue simulation framework for emergency department triage
Project description
TriageSim
TriageSim is an open-source Python framework for generating synthetic, multi-speaker spoken dialogues for emergency department (ED) triage. It produces paired structured EHR → dialogue data grounded in real clinical vignettes, enabling controlled evaluation of speech and language systems in healthcare.
Features
- Nurse ↔ patient dialogue simulation via LLM agents (OpenRouter)
- Two triage algorithms: ESI (Emergency Severity Index) and ATS (Australasian Triage Scale)
- Persona-conditioned generation: diverse patient and nurse personas (ethnicity, experience, communication style, etc.)
- Structured run artifacts: belief state, red-flag trace, per-turn triage reasoning
- Pluggable LLM backends: any OpenRouter-compatible model (Claude, Gemini, GPT, etc.)
- Optional audio rendering: XTTS-v2 voice cloning for multi-speaker TTS synthesis
Installation
pip install triagesim
With Redis state store:
pip install "triagesim[redis]"
With audio rendering (requires PyTorch):
pip install "triagesim[audio]"
Or install the latest development version directly from GitHub:
pip install "git+https://github.com/dipankarsrirag/triage-sim.git"
Configuration
Set your OpenRouter API key as an environment variable or in a .env file at your project root:
export OPENROUTER_API_KEY=sk-or-...
# .env
OPENROUTER_API_KEY=sk-or-...
Quick Start
from triagesim import TriageRunner, RunnerConfig
from triagesim.agents import OpenRouterLLM, NurseAgent, PatientAgent
from triagesim.core import NurseOutput, PatientOutput
from triagesim.personas import (
load_patient_personas,
load_nurse_personas,
sample_patient_personas,
sample_nurse_personas,
)
# Load personas from YAML files
patients = load_patient_personas("path/to/patient.yaml")
nurses = load_nurse_personas("path/to/nurse.yaml")
patient_persona = sample_patient_personas(patients, k=1, seed=42)[0]
nurse_persona = sample_nurse_personas(nurses, k=1, seed=42)[0]
# Ground-truth clinical vignette (NOT visible to agents)
ground_truth = {
"chiefcomplaint": "Syncope",
"vitals": {
"temperature": 99.1,
"heartrate": 112,
"resprate": 26,
"o2sat": 91,
"sbp": 98,
},
"acuity": 2,
"pain": 7,
}
# Instantiate LLM backends — one per agent, each typed to its output schema
model = "anthropic/claude-sonnet-4-5"
patient_llm = OpenRouterLLM(model_name=model, output_type=PatientOutput)
nurse_llm = OpenRouterLLM(model_name=model, output_type=NurseOutput)
# Instantiate agents
patient = PatientAgent(llm=patient_llm, persona=patient_persona)
nurse = NurseAgent(llm=nurse_llm, persona=nurse_persona, algorithm="esi") # or "ats"
# Run
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()
Persona Format
Personas are loaded from YAML files. Each file is a list of persona dicts.
Patient persona fields:
- 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
response_length: medium
Nurse persona fields:
- gender: female
ethnicity: Australian
experience_level: senior
risk_tolerance: low
guideline_adherence: high
communication_style: direct
verbosity: medium
emotional_expression: neutral
Run Artifact
runner.run() returns a dict:
| Key | Description |
|---|---|
run_id |
Unique run identifier |
ground_truth |
The input clinical vignette |
history |
Full dialogue turn list (utterances + vitals + events) |
trace |
Per-turn nurse cognition trace (actions + reasoning) |
belief |
Final inferred belief state |
red_flags |
Red flags logged during triage |
state |
Final simulation state |
Evaluation Metrics
from triagesim.utils import compute_all_metrics
metrics = compute_all_metrics(
trace=artifact["trace"],
belief=artifact["belief"],
ground_truth=ground_truth,
)
# Returns: triage accuracy, belief coverage, red-flag P/R/F1, explanation stats
Using Redis State Store
config = RunnerConfig(
max_turns=20,
store_backend="redis",
redis_db=0,
seed=42,
)
Requires a running Redis instance and pip install "triagesim[redis]".
Custom LLM Backends
Subclass BaseLLM to use any model provider:
from triagesim.agents import BaseLLM
class MyLLM(BaseLLM):
def generate(self, prompt, **kwargs):
# call your model here
...
Citation
If you use TriageSim in your research, please cite:
@misc{srirag2026triagesimconversationalemergencytriage,
title={TriageSim: A Conversational Emergency Triage Simulation Framework from Structured Electronic Health Records},
author={Dipankar Srirag and Quoc Dung Nguyen and Aditya Joshi and Padmanesan Narasimhan and Salil Kanhere},
year={2026},
eprint={2603.10035},
archivePrefix={arXiv},
primaryClass={cs.CL},
url={https://arxiv.org/abs/2603.10035},
}
License
MIT © Dipankar Srirag
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file triagesim-0.1.1.tar.gz.
File metadata
- Download URL: triagesim-0.1.1.tar.gz
- Upload date:
- Size: 40.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd1f0c436a8ee26236d3246735265c4fbfface6525ed190826f60524e696bf68
|
|
| MD5 |
cb629e4da5c958247ace4cd6aec3016c
|
|
| BLAKE2b-256 |
480e186f6ba46aa954f0d477217d46cd64369570f640c08f9a0b0c3c800ad5a3
|
File details
Details for the file triagesim-0.1.1-py3-none-any.whl.
File metadata
- Download URL: triagesim-0.1.1-py3-none-any.whl
- Upload date:
- Size: 44.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b00aef02bb0cff2636616994e60ac65b8aa6079ec7c23f5a230222bce649acd0
|
|
| MD5 |
419ef8fc2de5e4e440ce71da474e8304
|
|
| BLAKE2b-256 |
a9df1873a0cb322ee10f765ef11c5fc637ba3bf61e9212ccd170c30b064e9606
|