TriVec Labs
All posts
RAGSeptember 1, 2026·7 min read

Automating Medical Coding Final Part

Once a medical coding pipeline maps a clinical concept to an ICD-10-CM code, it is tempting to declare victory and celebrate but story does not end here given…

RAG

Once a medical coding pipeline maps a clinical concept to an ICD-10-CM code, it is tempting to declare victory and celebrate but story does not end here

given a coding pipeline that generated the ICD code

Clinical concept
      ↓
 
Candidate retrieval
 
      ↓
 
LLM reasoning
 
      ↓
 
Validated ICD code
 

This is celebratory but It is also incomplete.

A hospital episode summmary rarely contains one diagnosis in isolation.

It contains active disease, chronic comorbidities, symptoms, historical conditions, ruled-out diagnoses, complications, procedures, and several diagnoses. All of these are correct but are not the final code of the episode.

Consider this simplified discharge summary:

DISCHARGE DIAGNOSES
 
1. Acute kidney injury secondary to dehydration.
2. Dehydration.
3. Chronic atrial fibrillation.
 
HOSPITAL COURSE
 
The patient was treated with IV fluids. Renal function improved.
 
Chronic atrial fibrillation remained rate controlled.
 
There was no evidence of acute myocardial infarction.
 
PAST MEDICAL HISTORY
 
Previous ischemic stroke.

A concept-level pipeline may produce:

Acute kidney injury → N17.9
 
Dehydration → E86.0
 
Chronic atrial fibrillation → validated AF code
 
Acute myocardial infarction → RULED OUT
 
Previous stroke → HISTORY

Every concept have been interpreted correctly. However, the chain of questions have only just started.

  1. Which diagnoses belong in the final episode?

  2. Which one is principal?

  3. Does the chronic atrial fibrillation meet the criteria for an additional diagnosis?

  4. Are symptoms separately reportable?

  5. Does one code need to be sequenced before another?

  6. Do multiple diagnoses collapse into a combination code?

That is the difference between coding a diagnosis and coding an episode.

Quip: Finding the right code is like buying all the super ingredients in a restaurant. Episode coding is figuring out which ones actually belong in a given recipe.

The Paradigm shift

Up to this point, the pipeline has been asking:

“What does this documented condition map to?”

Episode coding asks something fundamentally different

“Given everything we now know about the admission, what should the final coded representation of the hospitalization look like?”

That distinction deserves its own architecture. Coders workflow looks something like

                Discharge Summary
                       │
                       ▼
                Concept Extraction
                       │
                       ▼
                Concept Coding
                       │
                       ▼
          Validated Concept Decisions
                       │
                       ▼
              Episode Adjudication
          ┌────────────┼────────────┐
          ▼            ▼            ▼
   Reportability   Relationships   Rules
          │            │            │
          └────────────┼────────────┘
                       ▼
              Principal Diagnosis
                       │
                       ▼
                  Sequencing
                       │
                       ▼
               Final Episode Codes

The crucial part is that the episode layer does not silently recode the diagnosis from previous layers.

If the concept layer decided:

C1 → N17.9

the episode layer should not converge to

Actually, I fancy N17.8 today.

Its job is not to rewrite classification truth.

Its job is to determine whether C1 belongs in the final episode, and what role it plays.

Senior-engineer tip: When one stage answers “what is it?” and another answers “what do we do with it?”, keep those concerns separate. Otherwise debugging session leads to an archaeological expedition.


Step 1: Reportability comes after correctness

One of the common misconception is that a correctly coded concept becomes part of the final episode.

Consider:

Past medical history:
    Essential hypertension

the concept pipeline maps it to:

I10

This means:

If this condition is being coded, then I10 code represents it

It does not yet answer:

Should it be reported for this hospitalization?

Those are independent deductions.

So make reportability an explicit decision in the pipeline

ConceptCodingDecision
        ↓
 
ReportabilityDecision

For example:

Acute kidney injury
documented at discharge     ✓
evaluated during stay       ✓
treated                     ✓
    → REPORTABLE

Compare that with:

Hypertension
    appears only in PMH
    no medication adjustment
    no monitoring mentioned
    no effect on management
        → NOT_REPORTABLE / NEEDS_REVIEW

The system should converge on the evidence, not on the presence of a diagnosis.

Quip: A diagnosis appearing somewhere in the chart is not the same as it applying for permanent residency on the claim.


Step 2: Symptoms need their own adjudication

Suppose a patient presents with:

fever
cough
shortness of breath

discharge diagnosis is

Pneumococcal pneumonia

concept extractor should still detect the symptoms. They are indeed useful But they should not become separately reported diagnosis.

The episode layer needs to ask whether the symptom is

independent ?
integral to a confirmed diagnosis ?
explained by a confirmed diagnosis ?
still clinically significant on its own ?

This should be modelled as

SymptomConcept
  ↓
SymptomReportabilityEvaluator
      ↓
REPORTABLE
or
EXPLAINED_BY_CONFIRMED_DIAGNOSIS
or
INTEGRAL_TO_DIAGNOSIS
or
NEEDS_REVIEW

A suitable approach is to combine all of the following

clinical relationships
evidence
retrieved guideline context
constrained reasoning

and then make the system explain why a symptom was suppressed.

Pro tip: Suppression rules should be explainable. “Because this giant dictionary said so” is indeed an explanation, albeit a weak one.


Step 3: Clinical relationships matter, but they are not coding rules

The extraction layer may discover relationships like

Acute kidney injury
CAUSED_BY
 
Dehydration
 
or:
 
Postoperative wound infection
 
    COMPLICATION_OF
 
Appendectomy

These relationships can influence

  1. guideline retrieval

  2. principal-diagnosis reasoning

  3. combination-code analysis

  4. complication logic

But they should not automatically dictate code order. This distinction is important.

A clinical edge:

AKI ── CAUSED_BY ──► Dehydration

means something about medicine.

A sequencing edge:

CODE_A ── MUST_PRECEDE ──► CODE_B

means something about classification rules.

These are not the same graph.

Quip: “A caused B” is medical relationship. “A must be printed before B” is bureaucracy. Both matter, but bureaucracy a little more


Step 4: Principal diagnosis needs its own reasoning stage

The principal diagnosis is not necessarily:

the first diagnosis in the note
 
nor:
the most severe diagnosis
 
nor:
the diagnosis with the highest LLM confidence
 
nor even:
the one that generated the largest bill

The principal diagnosis determination needs to look at the circumstances of the admission and the condition established after study as chiefly responsible for that admission.

For our earlier example:

Acute kidney injury
Dehydration
Chronic atrial fibrillation

There may have evidence like:

poor oral intake
dizziness
weakness
abnormal renal function
AKI confirmed
AKI attributed to dehydration
IV fluids given

The system should build structured principal-diagnosis candidates.

EPISODE_CANDIDATE_1
 
Diagnosis: Acute kidney injury
 
Admission relevance: strong
 
Established after study: yes
 
Treated: yes
 
Evidence: E1, E2, E3

versus:

EPISODE_CANDIDATE_3
 
Diagnosis: Chronic atrial fibrillation
 
Admission relevance: weak
 
Established after study:
already known chronic condition
 
Treatment:
no specific intervention
 
Monitoring:
yes

Now the reasoning task is far narrower. Instead of asking the LLM:

“What is the principal diagnosis?”

it gets three reportable candidates, admission evidence, clinical relationships , relevant official guideline context

and returns one of

EPISODE_CANDIDATE_1 
EPISODE_CANDIDATE_2 
EPISODE_CANDIDATE_3 
ABSTAIN

No arbitrary code ever gets generated the LLM stays grounded.

Pro tip: Principal diagnosis selection is an adjudication problem, not a popularity contest among diagnoses.


Step 5: The sequencing graph

This is where the architecture becomes pleasantly boring again.

Suppose final reportable diagnosis candidates are

A
B
C
D

and authoritative ICD instructions produce these dependencies:

A must come before B
B must come before C
A must come before D
 
Represented as:
A ─────► B ─────► C
 
│
 
└──────► D

Now you have a directed sequencing constraint graph.

An edge means exactly one thing:

The source code must precede the target code.

It does not mean:

source caused target
source is principal
source is more severe
source has a lower ICD number

This graph can be generated from things like:

CODE FIRST
USE ADDITIONAL CODE
etiology/manifestation instructions
other authoritative sequencing constraints

That is valuable because code sequencing stops being an informal collection of procedural rules. It becomes a graph problem.

Quip: When coding rules start forming dependencies, reach for a DAG before reaching for another rule table.


Step 6: Combination codes complicate things further

Episode coding is not always

one concept = one code

Sometimes two documented concepts may be represented by a combination code. Other times multiple codes are still required. The important thing is not to let the LLM improvise here

A combination-code evaluator should use

Alphabetic Index 
Tabular instructions 
inclusion terms 
clinical relationships 
guideline context

and produce something like:

NO_COMBINATION
 
COMBINATION_ALREADY_RESOLVED
 
POTENTIAL_COMBINATION
 
SEPARATE_CODES_REQUIRED
 
NEEDS_REVIEW

If a potential combination code was never validated through the concept-level pipeline, It should rather return

NEEDS_REVIEW

instead of silently substituting a brand-new code.


Step 7: Validate the whole episode again

Even after all this while, run a final validator on the pipeline (always)

Validator should check:

every code exists
principal diagnosis is reportable
no ruled-out diagnosis leaked in
no history-only diagnosis leaked in
no duplicate final code exists
all sequencing constraints are satisfied
all guideline references exist
all emitted codes came from validated concept decisions

If any unresolved issue remains then

NEEDS_REVIEW

is a perfectly acceptable result. This is especially important in healthcare.

Quip: “Needs review” is not a failure state. It is what honesty looks like in a production system.

Step 8: Evaluation now needs multiple layers

Once episode coding exists, a single F1 score becomes even less informative. Metrics are needed at every layer

For concept coding

candidate Recall@K 
exact code 
accuracy f
amily-level accuracy 
unsupported specificity

For episode coding

micro precision
micro recall 
micro F1 
exact episode-set match
 
For principal diagnosis:
 
principal diagnosis accuracy
principal abstention 
rate principal 
conflict rate

For safety

ruled-out 
leakage history 
rate sequencing violations
symptom overcoding

And for debugging

EXTRACTION_ERROR 
RETRIEVAL_ERROR 
CONCEPT_REASONING_ERROR
 REPORTABILITY_ERROR 
PRINCIPAL_DIAGNOSIS_ERROR
 SEQUENCING_ERROR 
VALIDATION_ERROR

These telemetry matters.

If an expected code never crossed candidate retrieval then there is no need to blame the principal diagnosis reasoner.

Quip: Blaming the LLM for a retrieval miss is like blaming the waiter because the chicken never had tomatoes.


Stage 10 : Synthetic episodes become even more valuable here

Concept-level synthetic tests are useful. Episode-level tests are better.

Generate Synthetic cases containing

active diagnosis
secondary chronic diagnosis
ruled-out diagnosis
historical diagnosis
symptoms
causal relationship

and freeze:

expected active set
expected principal code
expected exclusions

Now the evaluation is not merely

Did you retrieve N17.9?

It becomes:

Did you code the correct concepts?
Did you exclude the historical ones?
Did you exclude ruled-out disease?
Did you include the right additional diagnoses?
Did you choose the correct principal?
Did you satisfy sequencing rules?

That gets much closer to the actual engineering problem.

Pro tip: Synthetic data is excellent at making your assumptions explicit. Real data is excellent at proving those assumptions were incomplete.

The bigger engineering lesson

At first glance, medical coding looks like an NLP problem, Then it looks like a retrieval problem, Then a classification problem , And by the time you reach episode coding, it starts becoming

workflow engine
+
knowledge retrieval
+
constraint solver
+
LLM adjudicator

That is what a healthy evolution looks like

The closer we get to final coding truth, the more It becomes:

deterministic mechanics
 
explicit provenance
 
constraint graphs
 
structured decisions
 
safe abstention

over

"the model seemed confident"

That is the real difference between a demo and an engineering system.

The LLM remains important, but it becomes one component among several.


Final thought

The first phase of medical coding asks

What code represents this diagnosis?

The episode phase tries to answer

Given everything that happened during this hospitalization, what should the final coded story of the episode be?

That second question is harder. It also happens to be where good architecture starts paying dividends.

Because once classification truth, clinical interpretation and sequencing responsibility are separated cleanly, the model no longer has to know everything.

It only has to be good at the part we actually want it to do.

Final quip: The goal is not to build an LLM that runs the coding department. The goal is to build a coding system smart enough to know which decisions should never be delegated to the LLM.


Final Output