Building a Treatment Plan Explanation Agent: Helping Patients Understand Procedures
Build an AI agent that explains dental treatment plans in plain language, provides accurate cost estimates with insurance breakdowns, and presents financing options to help patients make informed decisions.
Why Patients Need Help Understanding Treatment Plans
Case acceptance is the single biggest revenue driver in a dental practice, and it hinges on patient understanding. Studies show that 40 percent of patients decline treatment not because they cannot afford it, but because they do not understand what is being recommended or why it matters. A treatment plan explanation agent bridges this gap by translating clinical terminology into language patients actually understand.
Procedure Knowledge Base
The foundation of the explanation agent is a structured database of dental procedures. Each entry contains the clinical name, CDT code, a plain-language explanation, and typical duration and recovery information.
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class ProcedureInfo:
cdt_code: str
clinical_name: str
layman_name: str
description: str
why_needed: str
what_to_expect: str
duration_minutes: int
recovery_notes: str
urgency_level: str # "routine", "soon", "urgent"
alternatives: list[str] = field(default_factory=list)
risks_if_delayed: str = ""
PROCEDURE_DB: dict[str, ProcedureInfo] = {
"D2740": ProcedureInfo(
cdt_code="D2740",
clinical_name="Crown - porcelain/ceramic substrate",
layman_name="Dental Crown",
description=(
"A crown is a custom-fitted cap that covers "
"your entire tooth. It is made of porcelain "
"that matches your natural tooth color."
),
why_needed=(
"When a tooth has a large filling, crack, or "
"has had a root canal, the remaining tooth "
"structure is weakened. A crown protects the "
"tooth from breaking and restores its shape "
"and function."
),
what_to_expect=(
"The procedure typically takes two visits. "
"At the first visit, the dentist reshapes the "
"tooth and takes impressions. A temporary crown "
"is placed. At the second visit, the permanent "
"crown is cemented in place."
),
duration_minutes=90,
recovery_notes=(
"Mild sensitivity for a few days is normal. "
"Avoid sticky foods for 24 hours."
),
urgency_level="soon",
alternatives=["Onlay (D2664)", "Extraction (D7210)"],
risks_if_delayed=(
"The weakened tooth may fracture, potentially "
"requiring extraction instead."
),
),
"D3310": ProcedureInfo(
cdt_code="D3310",
clinical_name="Endodontic therapy, anterior",
layman_name="Root Canal",
description=(
"A root canal removes infected or damaged "
"tissue from inside your tooth. The space "
"is cleaned, filled, and sealed."
),
why_needed=(
"When the nerve inside a tooth becomes "
"infected due to deep decay or injury, "
"a root canal saves the tooth by removing "
"the infection while keeping the outer "
"tooth structure intact."
),
what_to_expect=(
"The area is numbed with local anesthetic. "
"The dentist creates a small opening, removes "
"the infected tissue, cleans the canals, and "
"fills them. Most patients report the procedure "
"is no more uncomfortable than getting a filling."
),
duration_minutes=120,
recovery_notes=(
"Some soreness for 2-3 days, manageable with "
"over-the-counter pain medication. A crown is "
"usually recommended afterward."
),
urgency_level="urgent",
alternatives=["Extraction (D7210)"],
risks_if_delayed=(
"Infection can spread to the jaw bone and "
"surrounding tissues, causing an abscess "
"that requires emergency treatment."
),
),
}
Treatment Plan Builder
The agent assembles a complete treatment plan with cost breakdowns, sequencing recommendations, and priority ordering.
@dataclass
class TreatmentLineItem:
procedure: ProcedureInfo
tooth_number: int
fee: float
insurance_coverage: float
patient_cost: float
priority: int # 1 = highest priority
phase: int # treatment phase number
@dataclass
class TreatmentPlan:
patient_name: str
items: list[TreatmentLineItem]
total_fee: float = 0.0
total_insurance: float = 0.0
total_patient: float = 0.0
def calculate_totals(self):
self.total_fee = sum(i.fee for i in self.items)
self.total_insurance = sum(
i.insurance_coverage for i in self.items
)
self.total_patient = sum(
i.patient_cost for i in self.items
)
class TreatmentPlanBuilder:
def __init__(self, fee_schedule: dict, coverage: dict):
self.fees = fee_schedule
self.coverage = coverage
def build(
self, patient_name: str,
procedures: list[dict],
) -> TreatmentPlan:
items = []
for i, proc in enumerate(procedures):
code = proc["cdt_code"]
info = PROCEDURE_DB.get(code)
if not info:
continue
fee = self.fees.get(code, 0)
cov_pct = self.coverage.get(code, 0)
insurance_pays = fee * cov_pct / 100
patient_pays = fee - insurance_pays
items.append(TreatmentLineItem(
procedure=info,
tooth_number=proc["tooth"],
fee=fee,
insurance_coverage=insurance_pays,
patient_cost=patient_pays,
priority=proc.get("priority", i + 1),
phase=proc.get("phase", 1),
))
items.sort(key=lambda x: (x.phase, x.priority))
plan = TreatmentPlan(
patient_name=patient_name, items=items
)
plan.calculate_totals()
return plan
Plain Language Explanation Generator
The agent converts the structured treatment plan into a patient-friendly explanation. It avoids jargon, explains the reasoning behind each procedure, and groups treatments by phase.
See AI Voice Agents Handle Real Calls
Book a free demo or calculate how much you can save with AI voice automation.
class PlanExplainer:
def generate_explanation(
self, plan: TreatmentPlan,
) -> str:
sections = []
sections.append(
f"Treatment Plan for {plan.patient_name}\n"
)
phases = {}
for item in plan.items:
phases.setdefault(item.phase, []).append(item)
for phase_num in sorted(phases.keys()):
items = phases[phase_num]
sections.append(
f"## Phase {phase_num}\n"
)
for item in items:
p = item.procedure
sections.append(
f"**Tooth #{item.tooth_number}: "
f"{p.layman_name}**\n"
f"{p.description}\n\n"
f"*Why this is needed:* {p.why_needed}\n\n"
f"*What to expect:* {p.what_to_expect}\n\n"
f"*Time:* About {p.duration_minutes} minutes\n"
f"*Recovery:* {p.recovery_notes}\n\n"
f"*Cost:* ${item.fee:,.0f} total. "
f"Insurance covers ${item.insurance_coverage:,.0f}. "
f"Your cost: ${item.patient_cost:,.0f}.\n"
)
if p.risks_if_delayed:
sections.append(
f"*If treatment is delayed:* "
f"{p.risks_if_delayed}\n"
)
sections.append(
f"\n## Cost Summary\n"
f"Total fees: ${plan.total_fee:,.0f}\n"
f"Insurance pays: ${plan.total_insurance:,.0f}\n"
f"Your responsibility: ${plan.total_patient:,.0f}\n"
)
return "\n".join(sections)
Financing Options Calculator
For patients who cannot pay the full amount upfront, the agent presents financing options including in-house payment plans and third-party financing.
@dataclass
class FinancingOption:
name: str
monthly_payment: float
term_months: int
interest_rate: float
total_cost: float
approval_required: bool
class FinancingCalculator:
def calculate_options(
self, amount: float,
) -> list[FinancingOption]:
options = []
# In-house: 0% interest, short term
if amount <= 3000:
for months in [3, 6]:
options.append(FinancingOption(
name=f"In-house {months}-month plan",
monthly_payment=round(amount / months, 2),
term_months=months,
interest_rate=0.0,
total_cost=amount,
approval_required=False,
))
# Third-party financing
for months, rate in [(12, 0.0), (24, 9.9), (48, 14.9)]:
if rate == 0:
monthly = round(amount / months, 2)
total = amount
else:
r = rate / 100 / 12
monthly = round(
amount * r / (1 - (1 + r) ** -months), 2
)
total = round(monthly * months, 2)
options.append(FinancingOption(
name=f"CareCredit {months}-month plan",
monthly_payment=monthly,
term_months=months,
interest_rate=rate,
total_cost=total,
approval_required=True,
))
return options
FAQ
How does the agent handle procedures that are not in the knowledge base?
When the agent encounters a CDT code not in the procedure database, it falls back to the CDT code description from the American Dental Association's code set and flags it for the clinical team to provide a custom explanation. The agent never fabricates procedure descriptions — it transparently tells the patient that it will have the doctor provide more details about that specific procedure.
Can the agent adjust its explanations based on the patient's health literacy level?
Yes. The agent tracks patient interaction history and adjusts its language complexity accordingly. For patients who ask many follow-up questions, it provides more detailed analogies and simpler terms. For patients who seem comfortable with medical terminology, it includes more clinical detail. The PlanExplainer accepts a verbosity parameter that controls the level of detail.
How accurate are the cost estimates the agent provides?
The estimates are based on the practice's actual fee schedule and the patient's verified insurance benefits. They are accurate for the procedures listed but may not account for unexpected findings during treatment. The agent always includes a disclaimer that final costs may vary and encourages patients to discuss any concerns with the billing coordinator.
#TreatmentPlans #PatientEducation #DentalAI #CostEstimates #Python #AgenticAI #LearnAI #AIEngineering
CallSphere Team
Expert insights on AI voice agents and customer communication automation.
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.