Back to Blog
AI.NETHealthcareAzure OpenAIC#WPFClinical AIGPT-4o

AI-Assisted Clinical Decision Support in .NET: How to Help Healthcare Staff Without Replacing Their Judgement

AI in healthcare must be held to a higher standard than in any other domain. It must be accurate, auditable, and always deferential to clinical judgement. Here's how to build genuinely useful AI features into a healthcare records system symptom pattern recognition, medication safety checks, and clinical note generation without crossing the line into autonomous diagnosis.

30 April 202614 min read

AI in healthcare is one of the most consequential areas of software development. Get it wrong and real patients are harmed. Get it right and you genuinely help clinical staff make better-informed decisions, reduce documentation burden, and catch things that might otherwise be missed. The key word in that sentence is help — not replace, not automate, not decide.

This post describes three AI features built into a clinical records system using .NET and Azure OpenAI: intelligent medication safety screening, AI-assisted clinical note generation from structured data, and symptom pattern summarisation. Each is designed with a clear principle: AI surfaces information and flags concerns, clinicians make decisions.

The Core Principle: AI as a Second Pair of Eyes

The most useful mental model for healthcare AI is an extremely well-read, tireless colleague who has read every patient's file in full and can instantly recall any of it — but who defers all clinical judgement to the qualified professional in the room. The AI never says "the patient has X." It says "based on the documented symptoms, patterns consistent with X have been noted in the literature — please review."

Every implementation below follows three rules: always show the source data the AI used, always require confirmation before any AI-suggested action takes effect, and always log the AI output with a timestamp and the version of the model used.

Feature 1: AI Medication Safety Screening

A clinician is about to prescribe a new medication. The system should check it against the patient's full medication list — including historical medications, known allergies, and documented conditions — and surface any safety concerns before the prescription is confirmed.

public class MedicationSafetyService
{
    private readonly Kernel _kernel;

    public async Task<MedicationSafetyReport> ScreenAsync(
        PatientContext patient,
        string         proposedMedication,
        string         proposedDosage)
    {
        var currentMeds = string.Join(", ",
            patient.ActiveMedications.Select(
                m => $"{m.Name} {m.Dosage}"));

        var allergies = string.Join(", ",
            patient.Allergies.Select(a => a.Substance));

        var conditions = string.Join(", ",
            patient.DiagnosedConditions.Select(c => c.Name));

        var prompt = $"""
            You are a clinical pharmacology safety screening assistant.
            Review this proposed medication against the patient's current
            profile and identify any potential safety concerns.

            IMPORTANT:
            - Only flag evidence-based, clinically recognised interactions
            - Do not diagnose or make treatment recommendations
            - Rate severity using standard classifications only
            - If uncertain, err toward flagging for review

            Proposed medication: {proposedMedication} {proposedDosage}

            Patient profile:
            - Current medications: {currentMeds}
            - Known allergies: {allergies}
            - Diagnosed conditions: {conditions}
            - Age: {patient.Age}, Weight: {patient.WeightKg}kg
            - Renal function: {patient.RenalFunction}
            - Hepatic function: {patient.HepaticFunction}

            Return ONLY valid JSON:
            {{
              "safetyFlags": [
                {{
                  "type":        "DrugInteraction | Allergy | ContraIndication | DoseWarning",
                  "severity":    "Advisory | Moderate | Severe | Contraindicated",
                  "description": "string — what the concern is",
                  "mechanism":   "string — why this interaction occurs",
                  "clinicalNote": "string — what the prescriber should consider"
                }}
              ],
              "overallRating":     "Clear | ReviewAdvised | CautionRequired | Contraindicated",
              "requiresPhysicianReview": true/false,
              "screeningNotes":    "string"
            }}
            """;

        var result = await _kernel.InvokePromptAsync<string>(prompt,
            new KernelArguments(
                new PromptExecutionSettings
                {
                    ExtensionData = new() { { "temperature", 0.05 } }
                }));

        var report = JsonSerializer
            .Deserialize<MedicationSafetyReport>(result!)!;

        // Log every screening for audit trail — mandatory in clinical software
        await LogScreeningAsync(
            patient.Id,
            proposedMedication,
            report,
            modelVersion: "gpt-4o-2024-11-20");

        return report;
    }
}

Feature 2: AI Clinical Note Generation from Structured Data

One of the largest administrative burdens for healthcare staff is documentation. A nurse takes observations — blood pressure, temperature, pain scale, medication given — and then has to write a narrative note summarising what they observed and did. AI can generate a first draft of that note from structured input data in seconds, leaving the clinician to review, edit, and sign off rather than write from scratch.

public async Task<ClinicalNoteDraft> GenerateNoteAsync(
    ObservationSession session)
{
    // Format structured observations for the prompt
    var obsText = string.Join("\n",
        session.Observations.Select(o =>
            $"- {o.Metric}: {o.Value} {o.Unit} " +
            $"(Reference: {o.ReferenceRange}, " +
            $"Status: {o.Status})"));

    var medsGiven = string.Join("\n",
        session.MedicationsAdministered.Select(m =>
            $"- {m.Medication} {m.Dose} at {m.Time:HH:mm}"));

    var prompt = $"""
        You are a clinical documentation assistant.
        Generate a professional nursing/clinical observation note
        from these structured observations.

        The note should:
        - Use appropriate clinical language
        - Note any values outside reference ranges prominently
        - Be factual — do not interpret or diagnose
        - Be written in past tense (observations were taken)
        - Be suitable for a medical record
        - Be approximately 100-150 words

        Patient age: {session.PatientAge}
        Assessment time: {session.Timestamp:dd MMM yyyy HH:mm}
        Ward/Clinic: {session.Location}

        Observations:
        {obsText}

        Medications administered:
        {medsGiven}

        Staff member: {session.StaffName} ({session.StaffRole})

        Generate the clinical note now:
        """;

    var noteText = await _kernel.InvokePromptAsync<string>(prompt,
        new KernelArguments(
            new PromptExecutionSettings
            {
                ExtensionData = new() { { "temperature", 0.2 } }
            }));

    return new ClinicalNoteDraft
    {
        DraftText      = noteText,
        GeneratedAt    = DateTime.UtcNow,
        GeneratedBy    = "AI Draft — Requires Clinical Review",
        SourceDataHash = ComputeHash(session), // for audit integrity
        IsAIGenerated  = true,
        Status         = NoteStatus.PendingReview
        // Note cannot be saved to the medical record until
        // a qualified clinician reviews and signs off
    };
}

Feature 3: Symptom Pattern Summarisation for Handovers

Clinical handovers — when one shift ends and another begins — are a known high-risk moment in patient care. The outgoing clinician needs to brief the incoming one on every patient's current status. For a ward with 20 patients, this is a substantial communication task where things get missed. AI can generate a concise, structured handover summary from a patient's recent records.

public async Task<HandoverSummary> GenerateHandoverAsync(
    Guid patientId,
    DateTime periodStart,
    DateTime periodEnd)
{
    // Gather all clinical activity in the handover period
    var recentObs    = await _db.Observations
        .Where(o => o.PatientId == patientId &&
                    o.RecordedAt >= periodStart)
        .OrderByDescending(o => o.RecordedAt)
        .Take(20)
        .ToListAsync();

    var recentMeds   = await _db.MedicationAdministrations
        .Where(m => m.PatientId == patientId &&
                    m.AdministeredAt >= periodStart)
        .ToListAsync();

    var activeAlerts = await _db.ClinicalAlerts
        .Where(a => a.PatientId == patientId && !a.Resolved)
        .ToListAsync();

    // Build a structured summary for the AI
    var observationTrend = AnalyseObservationTrends(recentObs);

    var prompt = $"""
        Generate a clinical handover briefing for incoming staff.
        This is a factual summary only — no diagnosis, no prognosis.
        Structure: Current status → Key events → Active concerns → Watch points.
        Maximum 200 words.

        Patient: {patientId} | Period: {periodStart:HH:mm} to {periodEnd:HH:mm}

        Observation trends:
        {observationTrend}

        Medications given this period:
        {FormatMedications(recentMeds)}

        Active unresolved alerts:
        {string.Join("\n", activeAlerts.Select(a => $"- {a.Description}"))}

        Generate the handover briefing now:
        """;

    var summary = await _kernel.InvokePromptAsync<string>(prompt,
        new KernelArguments(
            new PromptExecutionSettings
            {
                ExtensionData = new() { { "temperature", 0.15 } }
            }));

    return new HandoverSummary
    {
        PatientId     = patientId,
        PeriodStart   = periodStart,
        PeriodEnd     = periodEnd,
        SummaryText   = summary,
        IsAIGenerated = true,
        GeneratedAt   = DateTime.UtcNow,
        // Incoming clinician must confirm they have read
        // and reviewed this before it is marked complete
        Status        = HandoverStatus.PendingIncomingReview
    };
}

Compliance, Audit, and the Non-Negotiables

Every AI feature in a healthcare system must meet these non-negotiable requirements regardless of jurisdiction:

Every AI output is logged — timestamp, model version, input data hash, output text, which staff member acted on it, and what action they took.

AI suggestions require explicit human confirmation — no AI output automatically changes a patient record. A clinician must review and confirm every time.

AI outputs are clearly labelled — any text generated by AI in the clinical record is marked as AI-generated at all times, including after signing off.

Model versions are pinned — you must know exactly which model version generated any clinical output. Use a fixed deployment name in Azure OpenAI, not the rolling alias.

These are not optional best practices — they are the baseline for responsible AI deployment in clinical environments, regardless of the regulatory framework in your region.

Building AI features into healthcare software? I've worked on clinical records systems and understand both the technical implementation and the sensitivity required. Happy to discuss the architecture.

Found this useful?

Share it with your network — it helps others find this too.

https://kathanpatel.vercel.app/blog/ai-healthcare-clinical-decision-support-dotnet-gpt4o-csharp